2015-09-24 14 views
10

Come posso verificare che varchar contenga tutti i caratteri di un altro varchar, dove la sequenza di caratteri è irrilevante?caratteri di controllo in varchar

Ad esempio: ho varchar @a = 'ABC' e colonna 'Col' nella tabella 'Table' dov'è fila con 'Col' = 'CBAD'. Voglio selezionare questa riga, perché contiene tutti i caratteri della variabile @a. Per favore, per il tuo aiuto.

ho provato qualcosa di simile:

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 

ma non posso mettere questo a WHERE condizioni

+0

quello che ha provato ?? –

+0

Le virgolette singole sono per valori letterali stringa/varchar. Non usare quelli per i nomi di colonne o tabelle. – jarlh

risposta

9

La prima necessità di dividere la variabile che si sta verificando in righe e rimuovere i duplicati. Per solo pochi caratteri si può semplicemente utilizzare una tabella valutata costruttore:

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) 

che dà:

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

Ora si può paragonare questo alla vostra colonna e limitarla solo per colonne in cui la colonna contiene tutte le lettere (fatto nella clausola 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) 
     ); 

Se la variabile può essere più lungo di 10 caratteri, quindi potrebbe essere necessario adottare uno stri leggermente diversa ng metodo di divisione. Vorrei ancora usare i numeri per fare questo, ma sarebbe invece utilizzare 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; 

questo vi darà una serie di numeri da 1 a 10.000, e si può semplicemente aggiungere più CTE e si unisce, se necessario, croce di estendere il processi. Quindi, con una stringa più lunga si potrebbe avere:

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

Si può provare in questo modo:

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

oppure si può provare a utilizzare PATINDEX

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

La seconda soluzione controlla solo l'esistenza di 1 carattere in colname. Darebbe lo stesso risultato della tua prima soluzione con OR invece di AND –

2

Un'altra versione:

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 
Problemi correlati