从行连接列值

时间:2009-06-25 10:18:23

标签: sql sql-server sql-server-2000

我正在使用带有SQL Server 2000后端的时间表系统我需要在旁边列出带有导师和房间的事件,这可能超过1,因此可以将多行房间和导师转换为+分隔列表。我过去使用过以下代码:

DECLARE @Tutors as varchar(8000)

SELECT @Tutors = isnull(@Tutors + ' + ', '') + name
FROM (
    SELECT CT_EVENT_STAFF.event_id, CT_EVENT_STAFF.weeks, 
        CT_STAFF.unique_name, CT_STAFF.name
    FROM celcat200809.dbo.CT_EVENT_STAFF AS CT_EVENT_STAFF 
    LEFT OUTER JOIN celcat200809.dbo.CT_STAFF AS CT_STAFF 
        ON CT_EVENT_STAFF.staff_id = CT_STAFF.staff_id
    WHERE event_id = @eventID
) As data_set

print @Tutors

event_id是唯一的事件,这只有在我知道确切的ID时才会起作用,我无法为每个ID运行它。

有没有办法为没有游标的每个单独的event_id执行此操作。我已经看到了使用UDF的可能解决方案,遗憾的是我的第二个问题是时间表系统(CELCAT)为每年创建一个新数据库(我知道不要问)所以我将不得不使SQL动态即接下来的几年数据库将是celcat200910,我相信动态SQL无法在UDF中运行。

请记住这是SQL Server 2000

5 个答案:

答案 0 :(得分:1)

您仍然可以使用视图作为goodgai建议,但不要将其重定向到一个表,让它联合选择表。如果尚未完成并且您需要它,可以将年/月分成列。

CREATE VIEW UNIFIED_CT_STAFF
AS
SELECT year = 2008, month = 9, unique_name, name FROM celcat200809.dbo.CT_STAFF
UNION SELECT year = 2008, month = 10, unique_name, name FROM celcat200810.dbo.CT_STAFF

答案 1 :(得分:0)

您可以创建一个UDF来计算字符串,然后使用它:

select event_id, dbo.GetTutorsText(@eventId)
from EventsTable

UDF可以定义为:

if object_id('dbo.GetTutorText') is not null 
    drop function dbo.GetTutorText
go
create function dbo.GetTutorText(
    @eventID int)
returns varchar(8000)
as
begin
DECLARE @Tutors as varchar(8000)

SELECT @Tutors = isnull(@Tutors + ' + ', '') + name
FROM (
    SELECT CT_EVENT_STAFF.event_id, CT_EVENT_STAFF.weeks, 
        CT_STAFF.unique_name, CT_STAFF.name
    FROM celcat200809.dbo.CT_EVENT_STAFF AS CT_EVENT_STAFF 
    LEFT OUTER JOIN celcat200809.dbo.CT_STAFF AS CT_STAFF 
        ON CT_EVENT_STAFF.staff_id = CT_STAFF.staff_id
    WHERE event_id = @eventID
) As data_set

return @Tutors
end
go

答案 2 :(得分:0)

对于第二个问题,请使用VIEW。为ce​​lcat数据库中的每个感兴趣的表创建一个视图,并改为使用视图。

当数据库进展到下一年时,只需更新所有视图以指向新数据库。使用VIEW的系统中的每个查询现在都将寻址正确的数据库。

答案 3 :(得分:0)

  • 请问您为什么需要连接服务器上的名称?客户端应用程序无法为您执行此操作吗?

  • 如果您在寻找其他数据库中的表时遇到问题,请使用标准化名称创建视图,每个表一个,只需从每个表中选择*即可。您可以编写一个自动创建视图的SP,让您只传入要设置所有视图的数据库的名称。这些观点不会以任何重大方式损害表现。

  • 由于您正在使用左连接到CT_STAFF,这使我相信工作人员可能会丢失,在这种情况下,您将丢失连接它们的表达式的数据,因为它不允许NULL员工姓名(每次遇到NULL员工姓名时都会重置列表)。

这是一个可以做你需要的查询,虽然它有点像黑客:

SELECT
   seqid = identity(int, 1, 1),
   event_id,
   S.name
INTO #EventNames
FROM
   celcat200809.dbo.CT_EVENT_STAFF ES
   LEFT JOIN celcat200809.dbo.CT_STAFF S ON ES.staff_id = S.staff_id
ORDER BY
   event_id,
   S.name --optional, whatever you like here.

SELECT
   EN.event_id,
   Max(CASE seqid - minseqid WHEN 0 THEN EN.name ELSE '' END))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 1 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 2 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 3 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 4 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 5 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 6 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 7 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 8 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 9 THEN EN.name ELSE NULL END, ''))
   + Max(Coalesce(' + ' + CASE seqid - minseqid WHEN 10 THEN EN.name ELSE NULL END, ''))
FROM
   #EventNames EN
   INNER JOIN (
      SELECT event_id, minseqid = Min(seqid) FROM #EventNames GROUP BY event_id
   ) X ON EN.event_id = X.event_id
GROUP BY EN.event_id

确保将足够的Max()表达式放入每个事件中,以覆盖尽可能多的人员。

要获取有关该事件的更多数据,请不要将其放在临时表中(这会使其变慢)。只需将此大查询用作自己的派生表,然后再连接到所需的表。

答案 4 :(得分:0)

过去几个月我做了一些软体开发 - 这有点像噩梦,我很同情你!

老实说,在这种情况下,您可能会更好地使用Celcat API(这需要一些习惯,但功能非常强大,并且具有以下优势:您的查询应该在各版本之间相当安全。)

我创建了一个类,我用它来选择特定的数据库版本等,创建一个特定于我想要使用的学年的会话。

在API中,如果需要,还可以选择直接运行SQL。

我知道这不能回答你的问题,但我希望它能解决你的问题!