J'ai une table [CourseMaster]
COMME
CourseId CourseName
-----------------------
01 ABC
02 DEF
03 GHI
04 JKL
05 MNO
06 PQR
07 STU
Et j'ai une autre table [StudentMaster]
pour les détails des étudiants COMME
ROLLNO NAME ADDRESS Course
------------------------------------------------
12345 RAM RAM ADDRESS 01,02,06
25695 HARI HARI ADDRESS 02,06
89685 JEFF JEFF ADDRESS 03,05,06,07
47896 DAISY DAISY ADDRESS 03
Ici, je veux récupérer les détails de l'étudiant avec CourseName
(pas CourseId
).
Si les valeurs dans Course
ne sont pas séparées par des virgules, il serait très simple query
de récupérer les détails avec join.
À ma connaissance, je peux exécuter deux queries
pour le même résultat que je veux, une requête pour récupérer les détails de l'étudiant à partir de [StudentMaster]
à l'extrémité avant. Et un autre pour récupérer uniquement le CourseName
de [CourseMaster]
par CourseId
correspondant dans une boucle.
Mais le fait que je veux le résultat par un seul query
plutôt que d'écrire deux queries
pour cette petite tâche.
Je suppose que c'est 100% possible. Et mon résultat attendu ressemblera à:
ROLLNO NAME ADDRESS Course
-------------------------------------------
12345 RAM RAM ADDRESS ABC,DEF,PQR
25695 HARI HARI ADDRESS DEF,PQR
89685 JEFF JEFF ADDRESS GHI,MNO,PQR,STU
47896 DAISY DAISY ADDRESS GHI
Merci et toute suggestion utile sera très appréciée.
Vous devriez vraiment avoir une table de jonction pour les cours suivis par un étudiant, plutôt que de brouiller les valeurs séparées par des virgules dans un seul tuple. Si vous pensez que c'est le dernier problème que vous aurez à cause de cette conception sous-optimale, vous êtes dans une grande surprise. Vous devriez vraiment demander aux propriétaires de ce projet de lire sur la normalisation - oui, il est douloureux de changer votre schéma, mais il est donc constamment confronté aux limites de le laisser tel quel.
Quoi qu'il en soit, cela dit, vous avez besoin d'une fonction partagée. Étant donné que vos valeurs séparées par des virgules sont numériques, vous pouvez vous en sortir avec une variation de ma fonction XML; il y en a plusieurs autres au choix dans cet article de blog .
CREATE FUNCTION dbo.SplitStrings_XML
(
@List VARCHAR(MAX),
@Delimiter CHAR(1) = ','
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'varchar(8000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
Maintenant, votre requête est:
;WITH x AS
(
SELECT s.ROLLNO, s.Name, s.Address, c.CourseId, c.CourseName
FROM dbo.StudentMaster AS s
CROSS APPLY dbo.SplitStrings_XML(s.Course, default) AS f
INNER JOIN dbo.CourseMaster AS c
ON f.item = c.CourseId
)
SELECT ROLLNO, Name, Address, STUFF((
SELECT ',' + CourseName FROM x AS x2
WHERE x2.ROLLNO = x.ROLLNO
ORDER BY CourseId FOR XML PATH,
TYPE).value(N'.[1]',N'varchar(max)'), 1, 1, '')
FROM x
GROUP BY ROLLNO, Name, Address;
Encore une fois, c'est une solution compliquée, et en raison de votre structure de base de données inférieure, la prochaine requête que vous devrez effectuer sera également alambiquée et encombrante. Il y a une raison pour laquelle ce type de conception est contesté dans presque tous les blogs, essais ou livres sur le sujet ...
Même solution que celle proposée par Aaron Bertrand pour la construction des valeurs séparées par des virgules mais un peu différente pour la connexion de CourseMaster.CourseId
avec les valeurs dans StudentMaster.Course
.
Configuration du schéma MS SQL Server 2014 :
create table dbo.CourseMaster
(
CourseId char(2),
CourseName char(3)
);
create table dbo.StudentMaster
(
ROLLNO char(5),
NAME varchar(10),
ADDRESS varchar(20),
Course varchar(100)
);
insert into dbo.CourseMaster values
('01', 'ABC'),
('02', 'DEF'),
('03', 'GHI'),
('04', 'JKL'),
('05', 'MNO'),
('06', 'PQR'),
('07', 'STU');
insert into dbo.StudentMaster values
('12345', 'RAM', 'RAM ADDRESS', '01,02,06'),
('25695', 'HARI', 'HARI ADDRESS', '02,06'),
('89685', 'JEFF', 'JEFF ADDRESS', '03,05,06,07'),
('47896', 'DAISY', 'DAISY ADDRESS', '03');
Requête 1 :
select SM.ROLLNO,
SM.NAME,
SM.ADDRESS,
(
select ','+CM.CourseName
from dbo.CourseMaster as CM
where ','+SM.Course+',' like '%,'+CM.CourseId+',%'
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as Course
from dbo.StudentMaster as SM;
| ROLLNO | NAME | ADDRESS | Course |
|--------|-------|---------------|-----------------|
| 12345 | RAM | RAM ADDRESS | ABC,DEF,PQR |
| 25695 | HARI | HARI ADDRESS | DEF,PQR |
| 89685 | JEFF | JEFF ADDRESS | GHI,MNO,PQR,STU |
| 47896 | DAISY | DAISY ADDRESS | GHI |
Un moyen simple pour obtenir les valeurs de la liste à partir de la table StudentMaster
(et vous pouvez vous joindre aux résultats) serait de (à l'aide d'une chaîne fractionnée comme mentionné dans les réponses précédentes, et en supposant que la fonction renvoie une colonne appelée pour chaque élément de la liste):
SELECT ROLLNO, NAME, ADDRESS, item
FROM StudentMaster
CROSS APPLY fSplitString(Course);
select D.DATE,D.DESCP,
(
select ','+S.NAME
from tb_schems as S
where ',' + D.SCHME + ',' like '%,' + cast(S.id as nvarchar(20)) + ',%'
for xml path(''), type
).value('substring(text()[1], 2)', 'varchar(max)') as SCHEME
from TB_DETAIL as D;