2016-08-11 6 views
0

Ein Feld in der Tabelle enthalten, das zwischen 1, 2 oder 3 Ziffern enthalten kann, die durch Kommas getrennt sind. Also wie folgt Beispiel unten:Datensätze erhalten, deren Feld bestimmte Ziffern enthält

ID | digitField 
1 | 4, 55 
2 | 1 ,70,33 
3 | 8 
4 | 9,22,43 
5 | 1,833,3 
6 | 77,9 
7 | 33 
8 | 2,3335 
9 | 6, 33 

Jetzt mit einer Ziffer möchte ich suchen und erhalten ID der Datensätze, die es enthält. Was ist der beste Ansatz, um nach diesen Datensätzen zu suchen? jedes Auftreten von Ziffer 33. In diesem Fall

Zum Beispiel für suche ich würde Ich mag diese Datensätze erhalten, basierend auf obiges Beispiel:

2 | 1,70,33 
7 | 33 
9 | 6, 33 

Hat folgende Abfrage wäre gut genug und nicht riskant zu bekommen falsche Ergebnisse, oder könnten Sie bessere Lösung geben ?:

SELECT ID FROM table WHERE CONTAINS(digitField, '33'); 

Diese Abfrage ist sehr wichtig als Ergebnis ids Shop-Produkte löschen wird, so dass ich zu falschen Ergebnissen vermeiden möchten. Beachten Sie, dass Datensätze, die 3, 833 oder 3335 enthalten, nicht übereinstimmen können, wenn wir nach 33 suchen. Beachten Sie auch, dass einige Leerzeichen innerhalb dieses Felds vorhanden sein können (das ist bereits implementiert und kann nicht geändert werden)

Auf der Suche nach der besten Lösung.

Zusätzliche Frage richtig Abfrage innerhalb Zeichenfolge close up:

Using cnn As New SqlConnection(strcon) 
cnn.Open() 
'--Just in case remove all spaces from string in field Materials before 
Using dad As New SqlDataAdapter(";WITH yourtable as (SELECT ID, REPLACE(digitField, ' ', '') digitfield FROM tempDigit) 
         SELECT * FROM YourTable WHERE digitField = @matId 
         OR digitField LIKE @matId+',%' 
         OR digitField LIKE '%,'[email protected] 
         OR digitField LIKE '%,'[email protected]+',%'", cnn) 
    dad.SelectCommand.Parameters.Add(New SqlParameter("@matId", matId.ToString)) 
    dad.Fill(dt) 
    If dt IsNot Nothing AndAlso dt.Rows.Count > 0 Then 
     result = dt 
    End If 
End Using 
cnn.Close() 
End Using 
+0

Haben Sie einen Volltextindex auf th Die Spalte 'digitField'? Andernfalls können Sie ['CONTAINS'] nicht verwenden (http://msdn.microsoft.com/en-us/library/ms187787.aspx) – NickyvV

+0

Falls Sie 'ID 3' als' 8333' haben, müssen Sie diese ebenfalls zurückgeben im Ergebnis? – Arulkumar

+0

Nein - nur genaue Nummer in diesem Fall 33 also nicht 3, aber wenn ich 3 wäre, dann 33 kann nicht zurückgegeben werden –

Antwort

0

Filtern Sie einfach alle möglichen Variationen der Vorkommen der gegebenen Zahl. Wenn Feld kann Leerzeichen enthält - entfernen Sie sie einfach.

SELECT * 
FROM YourTable 
CROSS APPLY (SELECT REPLACE(digitField, ' ', '') AS pureField) digit 
WHERE digit.pureField = @Exact  --if only one number in field 
    OR digit.pureField LIKE @Begin --if number in the beginning of text 
    OR digit.pureField LIKE @End --if number in the end of text 
    OR digit.pureField LIKE @Middle --if number in the middle of text 

Sql Parameter zu schaffen

Dim parameters As SqlParameter() = 
{ 
    New SqlParameter With {.ParameterName = "@Exact", .SqlDbType = SqlDbType.VarChar, .Value = matId.ToString()}, 
    New SqlParameter With {.ParameterName = "@Begin", .SqlDbType = SqlDbType.VarChar, .Value = $"{matId},%"}, 
    New SqlParameter With {.ParameterName = "@End", .SqlDbType = SqlDbType.VarChar, .Value = $"%,{matId}"}, 
    New SqlParameter With {.ParameterName = "@Middle", .SqlDbType = SqlDbType.VarChar, .Value = $"%,{matId},%"}, 
} 
+0

beachten, dass auch ihre Leerzeichen zwischen sein könnte - das ist etwas bereits implementiert ... –

+1

@JimmyJimm, entfernen Sie die Leerzeichen vor dem Vergleich der Daten. – Fabio

+0

Ich mag deine Antwort aber denke immer noch ob es noch keinen Fehler gibt oder etwas, das ein falsches Ergebnis zurückgeben könnte. Bist du sicher, dass das in jeder Situation funktionieren wird, wie ich es in meinem Post geschrieben habe? –

0

CHARINDEX Verwenden Sie das passende Ergebnis bekommen:

SELECT * 
FROM Table 
WHERE CHARINDEX('33', digitField) >= 1; 

Probe Ausführung mit dem angegebenen Beispieldaten:

DECLARE @TestTable TABLE (ID INT, digitField VARCHAR (200)); 

INSERT INTO @TestTable (ID, digitField) VALUES 
(1, '4, 55'), 
(2, '1,70,33'), 
(3, '8'), 
(4, '9,22,43'), 
(5, '1,2,3'), 
(6, '77,9'), 
(7, '33'), 
(8, '2,5'), 
(9, '6, 33'); 

SELECT * 
FROM @TestTable 
WHERE CHARINDEX('33', digitField) >= 1; 

Ausgabe:

ID digitField 
-------------- 
2 1,70,33 
7 33 
9 6, 33 
+0

schauen Sie denken, es ist so sicher, ich kann kein Ergebnis erhalten ? Wie ich seine sehr wichtige Frage erwähnt habe, werde ich Produkte aus der Datenbank entfernen. –

+0

Dies wird auch die Einträge wie '330' und' 833' ziehen. Sie müssen die Abfrage optimieren. – Arulkumar

+0

sollte es nicht 330 und 833 setzen, aber in diesem Fall 33 suchen wir nur nach 33 –

1

Sie benötigen eine Tabelle SPLIT Funktion "Entpivotisierung" Ihre digitField in Aufzeichnungen bewertet, so

ID | digitField 
1 | 4, 55 
2 | 1 ,70,33 
3 | 8 

ID | n | digitField 
1 | 1 | 4 
1 | 2 | 55 
2 | 1 | 1 
2 | 2 | 70 
2 | 3 | 33 
3 | 1 | 8 
werden wird

Dann suchen Sie in diesem Ergebnis nach Ihrer Nummer.

Es gibt viele Split-Funktionen um, google für sie.
Ich habe mein von mir entwickelt:

CREATE FUNCTION [dbo].[FN_SPLIT] 
/* 
    MTW - FN_SPLIT() 
    [email protected] 
*/ 
(
    @Line varchar(8000), 
    @SplitOn varchar(10) = ',' 
) 
RETURNS @RtnValue table 
(
    Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, -- VERY USEFUL TO MAKE JOINS AND TO CREATE THE UNIQUE INDEX ON SPLITTED STRINGS 
    Data varchar(800) NOT NULL, 
    UNIQUE (DATA, ID) -- THIS WILL MAKE REALLY FASTER THE QUERIES USING THIS FUNCTION 
) 
AS 
BEGIN 
    IF @Line IS NULL RETURN 

    DECLARE @split_on_len INT = LEN(@SplitOn+'X')-1 -- TO CATCH TRAILING SPACES PROBLEM WITH LEN() 
    DECLARE @line_len INT = LEN(@line+'X')-1 
    DECLARE @start_at INT = 1 
    DECLARE @end_at INT 
    DECLARE @data_len INT 

    WHILE 1=1 
    BEGIN 
     IF @start_at > @line_len BREAK; 
     SET @end_at = CHARINDEX(@SplitOn, @Line, @start_at) 
     SET @data_len = CASE @end_at WHEN 0 THEN @line_len ELSE @[email protected]_at END 
     INSERT INTO @RtnValue (data) VALUES(SUBSTRING(@Line,@start_at,@data_len)); 
     SET @start_at = @start_at + @data_len + @split_on_len 
    END 

    RETURN 
END 

so Ihre Anfrage wird:

;WITH 
S AS (
    SELECT T.ID, X.Id N, RTRIM(LTRIM(X.Data)) digitField 
    FROM T 
    CROSS APPLY (
     SELECT * 
     FROM FN_SPLIT(T.digitField, ',') F 
    ) X 
) 
SELECT * 
FROM S 
WHERE digitField = '33' 
ORDER BY 1,2 

das Ergebnis:

ID N digitField 
2 3 33 
7 1 33 
9 2 33 

wo Spalte N die Position Ihrer Zahl ist in die ursprüngliche digitField-Spalte

+0

thx für Ihre Zeit, aber es ist sehr lang, was denkst du über @Fabio Antwort wird es Requigments passen - ich fragte, weil es sehr kurz ist. Ich teste deine auch. –

+1

es ist nicht so lange .. die Funktion fn_split, müssen Sie es einmal ausführen .. und es wird "Bibliothek" in Ihrer Datenbank. Die Abfrage ist kurz und klar und gibt auch Informationen über die Position. @Fabio-Lösungen machen es auch, aber ich würde gerne auf großen Produkttabellen Leistung sehen. – MtwStark

Verwandte Themen