1

我目前正在使用 sql server 并编写一个存储过程来检索一些数据。我的要求如下:

Table A:PersonId,FirstName,LastName,Address,CourseId
(Primary Key For Table B,Foreign Key Here)
Table B:CourseDescription,CourseId

现在,对于每门课程,可能有多个学生注册了该课程。我的要求是连接每个学生LastNameFirstName。如果一门课程中有 3 个或更多学生,我们必须在结果中将另一个标志值设置为“Y”。我已经使用 temp table 完成了 Stored proc,并逐步更新它。我的存储过程也是这样的:临时表有列:

SeqId,CourseId,CourseDescription,StudentNameConcat,IsMoreThan3

首先我更新课程ID,描述。然后从这个表中,我根据序列 id(SeqId) 循环并检索学生姓名列表作为列值并将其连接到声明的变量中。

这种方法不好,因为它不是基于集合的方法,我相信在使用内部查询或循环连接的单个查询中必须有另一种方法。我仍在阅读并尝试在单个查询中实现它。但仍然没有得到任何线索。

4

4 回答 4

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)
于 2013-08-24T18:00:59.190 回答
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,但名称为空且元素数据为', ' + s.FirstName + ' ' + s.LastName. 之后,您将此 xml 作为 nvarchar(max) 使用value方法(这将保留名称中的所有特殊字符,如&or >)。在那之后,你的名字会被连接起来,但是你之前会有一个逗号,所以你需要使用stuff函数来剪切它。

sql fiddle demo

于 2013-08-24T19:22:15.013 回答
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 演示):

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;
于 2013-08-24T19:59:11.413 回答
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上的一个工作示例。
如果您想解释这是如何工作的,请给我留言。

于 2013-08-24T18:03:10.733 回答