2015-09-24 28 views
10

Jak mogę sprawdzić, czy varchar zawiera wszystkie znaki z innego varcharu, gdzie sekwencja znaków jest nieistotna?sprawdź znaki w varcharze

Na przykład: mieć varchar @a = 'ABC' i kolumnę 'Col' w tabeli 'Table' gdzie rząd z 'Col' = 'CBAD'. Chcę wybrać ten wiersz, ponieważ zawiera on wszystkie znaki ze zmiennej @a. Proszę o pomoc.

Próbowałem coś takiego:

DECLARE @a varchar(5) = 'ABCD' 
DECLARE @b varchar(5) = 'DCA' 

DECLARE @i int = 0 

DECLARE @pat varchar(30) = '' 
while @i <> len(@b) BEGIN 
    SET @i = @i + 1 
    SET @pat = @pat + '[' + @a + ']' 
END 

SELECT @pat 

IF @b LIKE @pat SELECT 1 
ELSE SELECT 0 

Ale nie mogę umieścić to na WHERE stanie

+0

co próbowałeś ?? –

+0

Pojedyncze cudzysłowy odnoszą się do literałów ciągowych/varchar. Nie używaj tych dla nazw kolumn lub tabel. – jarlh

Odpowiedz

9

Twoja pierwsza potrzeba, aby podzielić zmienną, którą sprawdzasz, na wiersze i usunąć duplikaty. Tylko kilka znaków można po prostu użyć tabeli wartościową konstruktora:

DECLARE @b varchar(5) = 'DCA'; 
SELECT DISTINCT Letter = SUBSTRING(@b, n.Number, 1) 
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS n (Number) 
WHERE n.Number <= LEN(@b) 

co daje:

Letter 
---------- 
D 
C 
A 

Teraz można porównać to do kolumny i ograniczyć ją tylko do kolumn gdzie kolumna zawiera wszystkie litery (wykonane w klauzuli HAVING)

DECLARE @b varchar(5) = 'DCA'; 

WITH Letters AS 
( SELECT DISTINCT Letter = SUBSTRING(@b, n.Number, 1) 
    FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS n (Number) 
    WHERE n.Number <= LEN(@b) 
) 
SELECT * 
FROM (VALUES ('AA'), ('ABCD'), ('ABCDEFG'), ('CAB'), ('NA')) AS t (Col) 
WHERE EXISTS 
     ( SELECT 1 
      FROM Letters AS l 
      WHERE t.Col LIKE '%' + l.Letter + '%' 
      HAVING COUNT(DISTINCT l.Letter) = (SELECT COUNT(*) FROM Letters) 
     ); 

Jeśli zmienna może być dłuższy niż 10 znaków, to być może trzeba przyjąć nieco inny stri ng metoda podziału. I nadal korzystać z numerów, aby to zrobić, ale zamiast używać Itzik Ben-Gan's stacked CTE method:

WITH N1 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS n (N)), 
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),  
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2) 
SELECT ROW_NUMBER() OVER(ORDER BY N) 
FROM N3; 

To daje zbiór liczb od 1 do 10000, a można po prostu dodać więcej CTE i krzyż łączy jak należy przedłużyć proces. Więc z dłuższym ciąg może mieć:

DECLARE @b varchar(5) = 'DCAFGHIJKLMNEOPNFEDACCRADFAE'; 

WITH N1 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS n (N)), 
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),  
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2), 
Numbers (Number) AS (SELECT TOP (LEN(@b)) ROW_NUMBER() OVER(ORDER BY N) FROM N3), 
Letters AS (SELECT DISTINCT Letter = SUBSTRING(@b, n.Number, 1) FROM Numbers AS n) 
SELECT * 
FROM (VALUES ('ABCDDCAFGHIJKLMNEOPNFEDACCRADFAEEFG'), ('CAB'), ('NA')) AS t (Col) 
WHERE EXISTS 
     ( SELECT 1 
      FROM Letters AS l 
      WHERE t.Col LIKE '%' + l.Letter + '%' 
      HAVING COUNT(DISTINCT l.Letter) = (SELECT COUNT(*) FROM Letters) 
     ); 
5

Możesz spróbować tak:

SELECT * FROM yourTable where colname like '%[A]%' 
         AND colname like '%[B]%' 
         AND colname like '%[C]%' 

lub można spróbować użyć PATINDEX

SELECT * FROM yourTable WHERE PATINDEX('%[ABC]%',colname) > 1 
+0

Twoje drugie rozwiązanie sprawdza tylko istnienie 1 znaku w colname. Dałoby to ten sam rezultat, co twoje pierwsze rozwiązanie z OR, zamiast AND –

2

Jeszcze jedna wersja:

DECLARE @a varchar(5) = 'ABCD' 
DECLARE @b varchar(5) = 'DCA' 

;WITH cte AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) rn 
FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) a(n) 
CROSS JOIN (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) b(n) 
), 
astring AS(SELECT DISTINCT SUBSTRING(@a, rn, 1) AS l FROM cte WHERE rn <= LEN(@a)), 
bstring AS(SELECT DISTINCT SUBSTRING(@b, rn, 1) AS l FROM cte WHERE rn <= LEN(@b)) 
SELECT CASE WHEN EXISTS(SELECT * FROM bstring WHERE l NOT IN(SELECT * FROM astring)) 
      THEN 0 ELSE 1 
     END AS result 
1
SELECT * FROM yourTable WHERE PATINDEX('%A%',colname) >= 1 and PATINDEX('%B%',colname) >= 1 AND PATINDEX('%C%',colname) >= 1