我目前正在使用sql server并编写存储过程来检索一些数据。 我的要求如下:
Table A:PersonId,FirstName,LastName,Address,CourseId
(Primary Key For Table B,Foreign Key Here)
Table B:CourseDescription,CourseId
现在,每门课程都可能有多名学生注册该课程。我的要求是连接每个学生 LastName , FirstName 。如果课程中有3个或更多学生,我们必须在结果中将另一个标志值设置为“Y”。我已经使用临时表完成了存储过程,并逐步更新它。 我的存储过程也是这样的: 临时表有列:
SeqId,CourseId,CourseDescription,StudentNameConcat,IsMoreThan3
首先我更新课程ID,说明。然后从这个表中我循环基于序列id(SeqId)并检索学生名称列表作为列值并在声明的变量中连接它。
这种方法并不好,因为它不是基于集合的方法,我相信在使用内部查询或循环连接的单个查询中必须有替代方法。我仍在阅读并尝试在单一查询。但仍然没有得到任何线索。
答案 0 :(得分:2)
您的数据结构未规范化。除非学生只能参加一门课程。这很糟糕,应予以纠正。
除此之外,您正在尝试模拟group concat
函数。这是一种方法。
SELECT courses.*,
LEFT(students , LEN(students)-1) AS students,
case when (select count(*) from @studentcourses where CourseId = courses.CourseId)>=3
then 'y' else 'n' end
FROM courses
CROSS APPLY
(
SELECT lastname + ' ' + firstname + ','
FROM studentcourses
WHERE courses.CourseId = studentcourses.CourseId
FOR XML PATH('')
) t (students)
答案 1 :(得分:2)
select
c.CourseId,
c.CourseDescription,
stuff(
(
select ', ' + s.FirstName + ' ' + s.LastName
from Students as s
where s.CourseId = c.CourseId
for xml path(''), type
).value('.', 'nvarchar(max)')
, 1, 2, '') as Students,
case
when (select count(*) from Students as s where s.CourseId = c.CourseId) >=3 then 'y'
else 'n'
end as flag
from Courses as c
简要说明。首先,将字符串连接到xml,但name为空,元素数据为', ' + s.FirstName + ' ' + s.LastName
。之后,您使用value
方法将此xml作为nvarchar(max)(这将保留名称中的所有特殊字符,如&
或>
)。在那之后,你将连接你的名字,但之前你会有一个逗号,所以你需要使用stuff函数来剪切它。
答案 2 :(得分:2)
您需要另一张表来跟踪每门课程注册的学生:
CREATE TABLE dbo.AsocCoursePerson(
AsocCoursePerson INT PRIMARY KEY,
CourseID INT NOT NULL REFERENCES dbo.Course(CourseID),
PersonID INT NOT NULL REFERENCES dbo.Person(PersonID)
);
解决方案(SQL Fiddle demo):
SELECT c.CourseID,
c.[Description] AS CourseDescription,
STUFF(oa.XmlCol.value('(/result/@PersonsFullName)[1]','NVARCHAR(MAX)'),1,1,'') AS StudentNameConcat,
ISNULL(oa.XmlCol.value('(/result/@PersonsCnt)[1]','INT'),0) AS StudentsCount,
CASE WHEN ISNULL(oa.XmlCol.value('(/result/@PersonsCnt)[1]','INT'),0) >= 3 THEN 'Y' ELSE 'N' END AS IsMoreThan3
FROM dbo.Course c
OUTER APPLY(
SELECT
(
SELECT p.FirstName + ' ' + p.LastName AS PersonFullName
FROM dbo.AsocCoursePerson asoc
JOIN dbo.Person p ON asoc.PersonID = p.PersonID
WHERE asoc.CourseID = c.CourseID
FOR XML RAW('row'), TYPE
).query('
<result
PersonsFullName="{for $p in /row return concat(",",$p/@PersonFullName)}"
PersonsCnt="{count(/row)}"
/>
') XmlCol
) oa;
答案 3 :(得分:1)
如果你想要做的只是标记每个人的课程,如果课程中至少有3人,请尝试这样的事情:
SELECT T1.COURSEID,
T2.COURSEDESCRIPTION,
FIRSTNAME + ' ' + LASTNAME StudentNameConcat,
CASE
WHEN COUNT(*)
OVER (
PARTITION BY t1.COURSEID) >= 3 THEN 1
ELSE 0
END IsMoreThan3
FROM TABLEA T1
INNER JOIN TABLEB T2
ON T1.COURSEID = T2.COURSEID
您可以查看SQL Fiddle上的工作示例 如果你想解释它是如何工作的,请给我留言。