Объединить значения столбцов из строк - PullRequest
0 голосов
/ 25 июня 2009

Я использую систему хронометража с бэкэндом 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 - уникальное событие, оно будет работать только тогда, когда я знаю точный идентификатор, я не могу запустить его для каждого идентификатора.

Есть ли способ сделать это для каждого отдельного event_id без курсоров. Я видел возможное решение этой проблемы при использовании UDF, к сожалению, моя вторая проблема - система хронометража (CELCAT) создает новую базу данных для каждого года (я знаю, не спрашиваю), поэтому мне придется сделать SQL динамическим, т.е. база данных следующих лет будет celcat200910, я считаю, что динамический SQL не может быть запущен в UDF.

Пожалуйста, помните, что это SQL Server 2000

Ответы [ 5 ]

1 голос
/ 30 июня 2009

Вы все еще можете использовать представление, как предложено 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
0 голосов
/ 13 июля 2009

За последние несколько месяцев я немного занимался разработкой celcat - это немного кошмар, и я сочувствую вам!

Если честно, в этой ситуации вам, вероятно, будет лучше использовать API Celcat (к которому нужно немного привыкнуть, но он достаточно мощный и имеет то преимущество, что ваши запросы должны быть достаточно безопасными в разных версиях).

Я создал класс, который использовал для выбора конкретных версий баз данных и т. Д., Создав сессию, специфичную для учебного года, который я хотел использовать.

В API также есть возможность прямого запуска SQL, если вам нужно.

Я знаю, что это не отвечает на ваш вопрос, но я надеюсь, что это решит вашу проблему!

0 голосов
/ 02 июля 2009
  • Могу я спросить, зачем вам нужно объединять имена на сервере? Разве клиентское приложение не может сделать это для вас?

  • Если у вас возникли проблемы с обращением к таблицам в других базах данных, создайте представления со стандартизованными именами, по одному на таблицу, которые просто выбирают * из каждой таблицы. Вы могли бы написать 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 (), чтобы охватить максимально возможное количество сотрудников на событие.

Чтобы получить больше данных о событии, не помещайте их в временную таблицу (это замедлит работу). Просто используйте этот большой запрос как собственную производную таблицу и присоединитесь к нужным таблицам.

0 голосов
/ 25 июня 2009

Для вашей второй проблемы используйте ВИД. Создайте представление для каждой интересующей вас таблицы в базе данных celcat и используйте вместо этого представления.

Когда база данных перейдет к следующему году, просто обновите все представления, чтобы указать на новую базу данных. Каждый запрос в системе, использующий VIEW, теперь будет обращаться к правильной базе данных.

0 голосов
/ 25 июня 2009

Вы можете создать 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
...