J'ai deux tables, appelons-les Users
et Fruit
.
Users
ID Name ------------- 1 Apple 2 Orange 3 Grape
Fruit
ID Name Fruit ------------------- 1 Bob 1,3 2 Jack 3
Comment joindre ces deux tables pour remplir une table de données avec le choix des utilisateurs des noms de fruits?
Aurais-je besoin d'écrire une procédure stockée avec un boucle?
Je suis plutôt nouveau dans SQL Server et je serais heureux de recevoir de l'aide ou d'être pointé dans la bonne direction.
5 Réponses :
Tout d'abord, vous devez repenser vos tableaux. Il y a besoin d'une table de jonction, qui contiendra quel utilisateur est connecté à quel fruit. C'est une relation N: N
.
Vous devez donc créer une telle table:
FruitUser
select * from users u join FruitUser fu on u.id = fu.userid join Fruit f on f.id = fu.fruitId
UserId est FK vers la table Users
, FruitId
est FK vers la table Fruits
et ces deux colonnes forment une clé primaire compoiste . C'est une approche standard.
Ensuite, vous pouvez utiliser une jointure simple pour obtenir des résultats:
UserId FruitId 1 1 1 3 2 3
Pour SQL Server 2014
où vous ne pouvez pas utiliser STRING_SPLIT
, vous pouvez diviser le varchar en utilisant XML
comme suit.
;WITH cte AS (SELECT id, name, fruitid FROM (SELECT *, Cast('<X>' + Replace(F.fruit, ',', '</X><X>') + '</X>' AS XML) AS xmlfilter FROM users F)F1 CROSS apply (SELECT fdata.d.value('.', 'varchar(50)') AS FruitId FROM f1.xmlfilter.nodes('X') AS fdata(d)) O) SELECT * FROM cte C INNER JOIN fruit F ON F.id = Cast(C.fruitid AS INT)
Exemple de données
Userid UserName FruitId FruitName ------------------------------------------ 1 Bob 1 Apple 1 Bob 3 Grape 2 Jack 3 Grape
Script Sql
;WITH CTE AS ( SELECT UserId, UserName , CAST(Split.a.value('.', 'nvarchar(1000)') AS INT) AS FruitId FROM ( SELECT u.ID AS UserId, u.Name AS UserName , CAST( '<S>'+ REPLACE(fruit,',','</S><S>')+'</S>' AS XML) AS FruitId FROM @Fruit f INNER JOIN @Users u ON u.ID=f.ID )AS A CROSS APPLY FruitId.nodes('S') AS Split(a) ) SELECT Userid, UserName, FruitId, ft.name AS FruitName FROM CTE c LEFT JOIN (SELECT * FROM @Fruit) AS Ft ON ft.ID=c.FruitId
Résultat
DECLARE @Users AS TABLE(ID INt, Name VARCHAR(100),fruit VARCHAR(100)) INSERT INTO @Users SELECT 1,'Bob' ,'1,3' UNION ALL SELECT 2,'Jack','3' DECLARE @Fruit AS TABLE(ID INt, Name VARCHAR(100)) INSERT INTO @Fruit SELECT 1,'Apple' UNION ALL SELECT 2,'Orange'UNION ALL SELECT 3,'Grape'
Merci pour votre réponse rapide, est-il possible d'avoir un nom d'utilisateur avec des noms de fruits sélectionnés séparés par des virgules dans une colonne?
Oui possible, nous pouvons écrire un script SQL
Vous pouvez obtenir le résultat souhaité sans rien changer avec cette requête
select * from (SELECT ID, [name],LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS fruitid FROM (SELECT ID,[name],CAST('<XMLRoot><RowData>' + REPLACE(fruit,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x FROM {User table})t CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)) u inner join {fruit table} f on f.id = u.fruitid
Puisque vous avez SQL Server 2014, vous avez diverses options telles que CLR, XML et les fonctions numériques. Le meilleur est CLR mais c'est complexe. Vous pouvez donc utiliser ce code XML.
SELECT u.Id, u.Name, f.name FROM Users u inner join Fruit f on f.ID IN (SELECT cast(value as int)FROM STRING_SPLIT(u.fruit, ','));
Création de tableaux physiques avec des exemples de données
ID Name FruitNames --------------------- 1 Bob Apple,Grape 2 Jack Grape
Créez une fonction table pour récupérer les noms des fruits séparés par des virgules
SELECT ID ,Name ,uf.Reqdata AS FruitNames FROM TempUsers u CROSS APPLY [dbo].[udf_GetFruitNames](u.Fruit) AS uf Or SELECT ID ,Name ,(SELECT Reqdata FROM [dbo].[udf_GetFruitNames](u.Fruit) ) AS FruitNames FROM TempUsers u
Requête SQL
CREATE FUNCTION [dbo].[udf_GetFruitNames] ( @vc_String nvarchar(max) ) RETURNS @OutTable TABLE ( Reqdata nvarchar(max) ) AS BEGIN DECLARE @Temp AS TABLE ( DATA nvarchar(max) ) INSERT INTO @Temp SELECT @vc_String; DECLARE @Temp1 AS TABLE ( DATA nvarchar(max) ) INSERT INTO @Temp1 SELECT STUFF((SELECT DISTINCT ','+ Name FROM ( SELECT ID, Name FROm TempFruit WHERE ID IN ( SELECT CAST(Split.a.value('.', 'nvarchar(1000)') AS INT) AS FruitId FROM ( SELECT CAST( '<S>'+ REPLACE(DATA,',','</S><S>')+'</S>' AS XML) AS FruitId FROM @Temp f )AS A CROSS APPLY FruitId.nodes('S') AS Split(a)) ) As dt FOR XML PATH ('')),1,1,'') As FruitName INSERT INTO @OutTable SELECT * FROM @Temp1 RETURN END
Résultat
CREATE TABLE TempUsers ( ID INT, Name VARCHAR(100), Fruit VARCHAR(100) ) INSERT INTO TempUsers SELECT 1,'Bob' ,'1,3' UNION ALL SELECT 2,'Jack','3' CREATE TABLE TempFruit ( ID INT, Name VARCHAR(100)) INSERT INTO TempFruit SELECT 1,'Apple' UNION ALL SELECT 2,'Orange'UNION ALL SELECT 3,'Grape'
Merci beaucoup mon pote, j'apprécie vraiment votre aide
@BryteNyte Heureux d'aider mon frère
Quelle est votre version de SQL Server?
Ne stockez jamais, jamais de données sous forme d'éléments séparés par des virgules. Cela ne vous causera que beaucoup de problèmes.
La bonne direction ne serait pas de stocker des valeurs séparées par des virgules, mais de normaliser votre base de données.
C'est Sql Server 2014.
Mon entreprise veut que je la sépare par une virgule comme ça
Supprimez la colonne de fruits de la table des utilisateurs. Créez plutôt une troisième table pour stocker l'utilisateur - fruit.
S'il s'agit d'une exigence de l'entreprise pour stocker des valeurs séparées par des virgules, n'y a-t-il pas un collègue qui peut vous conseiller comment c'est fait normalement?
@BryteNyte j'ai ajouté une autre réponse selon vos besoins, maintenir les données dans le coma séparé est une mauvaise pratique, comme les gens le suggèrent.