Свързване на стойности на колони от редове

Използвам система за разписание с бекенд на 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


person PeteT    schedule 25.06.2009    source източник
comment
Относно аранжиментите на DB: звучи грубо. Да, не се допуска динамичен SQL в UDF. Може да намерите полезна помощ в тази нишка за работа с множество DB: stackoverflow.com/questions/1037174/ ... обаче мисля, че най-доброто решение би било да се опитаме да намерим някакъв начин за поставяне на данните в една DB някъде - но това може да е по-горе и извън вашата компетентност/призвание.   -  person Joel Goodwin    schedule 25.06.2009
comment
Поставям повечето от данните в отделна база данни за данни за присъствие и други подобни. Използвам процедура за една нощ, за да попълня тези неща, но тази конкретна заявка трябва да е активна   -  person PeteT    schedule 26.06.2009


Отговори (5)


Все още можете да използвате изглед, както предлага 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
person Derek Flenniken    schedule 30.06.2009

За втория си проблем използвайте VIEW. Създайте изглед към всяка представляваща интерес таблица в базата данни Celcat и използвайте изгледите вместо това.

Когато базата данни премине към следващата година, просто актуализирайте всички изгледи, за да сочат към новата база данни. Всяка заявка в системата, използваща VIEW, вече ще адресира правилната база данни.

person Joel Goodwin    schedule 25.06.2009
comment
Знам какво казвате, но обикновено заявките всъщност използват няколко години база данни. Работя в колеж и Celcat, както и разписанието има присъствие на студенти, това се сравнява в партиди. - person PeteT; 25.06.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
person Andomar    schedule 25.06.2009
comment
връща varchar(4000) ДЕКЛАРИРАЙТЕ @Tutors като varchar(8000) tsk. цк. също isnull(@Tutors + ' + ', '') --› @Tutors + ' + ' никога не е null - person Coentje; 29.06.2009
comment
Коригиран е връщаният тип, но второто предложение е грешно: @Tutors ще бъде нула за първия намерен ред. - person Andomar; 29.06.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() изрази, за да покриете възможно най-голям брой служители на събитие.

За да получите повече данни за събитието, не го поставяйте във временната таблица (това ще го направи по-бавно). Просто използвайте тази голяма заявка като собствена производна таблица и се присъединете обратно към таблиците, от които се нуждаете.

person ErikE    schedule 02.07.2009

Разработих малко Celcat през последните няколко месеца - това е малко кошмар и ви съчувствам!

Ако трябва да бъда честен, в тази ситуация вероятно ще бъде по-добре да използвате Celcat API (с който трябва малко да свикнете, но е доста мощен и има предимството, че вашите заявки трябва да са доста безопасни във всички версии.)

Създадох клас, който използвах, за да избера конкретни версии на база данни и т.н., създавайки сесия, специфична за академичната година, която исках да използвам.

В рамките на API има и опция за директно стартиране на SQL, ако е необходимо.

Знам, че това не отговаря на въпроса ви, но се надявам да реши проблема ви!

person Hooloovoo    schedule 13.07.2009