J'ai une table qui contient un tas de nombres séparés par une virgule.
Je voudrais récupérer des lignes de la table où un nombre exact et non un nombre partiel se trouve dans la chaîne.
EXEMPLE :
CREATE TABLE IF NOT EXISTS `teams` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `uids` text NOT NULL, `islive` tinyint(1) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; INSERT INTO `teams` (`id`, `name`, `uids`, `islive`) VALUES (1, 'Test Team', '1,2,8', 1), (3, 'Test Team 2', '14,18,19', 1), (4, 'Another Team', '1,8,20,23', 1);
Je voudrais chercher où 1 est dans la chaîne.
Actuellement, si j'utilise Contains ou LIKE, il ramène toutes les lignes avec 1 , mais 18, 19 etc n'est pas 1 mais en a 1.
J'ai configuré un sqlfiddle ici
Dois-je faire un regex?
5 Réponses :
Vous pourriez probablement tous les attraper avec un OR
SELECT ... WHERE uids LIKE '1,%' OR uids LIKE '%,1' OR uids LIKE '%, 1' OR uids LIKE '%,1,%' OR uids = '1'
@Hogan Je ne dis jamais vraiment quand il s'agit de personnes stockant des données qui ne sont pas normalisées.
Je rechercherais les quatre emplacements possibles de l'ID que vous recherchez:
La requête ressemblerait à:
select * from teams where uids = '1' -- only or uids like '1,%' -- first or uids like '%,1' -- last or uids like '%,1,%' -- inner
uids = '1' - uniquement
Ça a changé. Même si LIKE
fonctionne, =
est plus intuitif.
Ouais, il pourrait être légèrement plus rapide s'il n'a pas besoin d'utiliser la correspondance de motifs.
Vous n'avez besoin que d'une condition:
select * from teams where concat(',', uids, ',') like '%,1,%'
@TheImpaler - bien sûr, il ajoute des virgules au début et à la fin.
Espérons simplement qu'il n'y ait pas d'espaces entre les virgules.
Vous n'avez pas spécifié la version de SQL Server que vous utilisez, mais si vous utilisez 2016+, vous avez accès à STRING_SPLIT que vous pouvez utiliser dans ce cas. Voici un exemple:
CREATE TABLE #T ( id int, string varchar(20) ) INSERT INTO #T SELECT 1, '1,2,8' UNION SELECT 2, '14,18,19' UNION SELECT 3, '1,8,20,23' SELECT * FROM #T CROSS APPLY string_split(string, ',') WHERE value = 1
Vous SQL Fiddle utilisez MySQL et votre syntaxe est cohérente avec MySQL. Il existe une fonction intégrée à utiliser:
select t.* from teams t where find_in_set(1, uids) > 0;
Cela dit, RÉPARER VOTRE MODÈLE DE DONNÉES POUR NE PAS STOCKER LES LISTES DANS UNE SEULE COLONNE. Désolé que cela soit sorti si fort, c'est juste un principe important de conception de base de données.
Vous devriez avoir une table appelée teamUsers
avec une ligne par équipe et par utilisateur de cette équipe. Il existe de nombreuses raisons pour lesquelles votre méthode de stockage des données est mauvaise:
uid
dans l'ordre ou la suppression des doublons sont inutilement difficiles.
Et c'est pourquoi vous ne stockez pas de données comme ça dans une table SQL.
Est-il trop tard pour prendre cette structure de table derrière la grange et la tirer, parce que c'est ce que vous devez faire ... Recommencez et structurez correctement ces données et cela vous fera gagner beaucoup de temps et de souffrances sur la route.
La meilleure façon de le faire est probablement d'utiliser une fonction de division de chaîne et de comparer avec les résultats