2009-06-25 8 views
0

J'utilise un système de calendrier avec SQL Server 2000 backend J'ai besoin de lister les événements avec des tuteurs et des salles à côté d'eux cela peut être plus de 1, donc faire tourner les multiples rangées de chambres et tuteurs dans + listes séparées. Je l'ai utilisé le code ci-dessous dans le passé:Concaténer les valeurs de colonne à partir des lignes

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 

Le event_id étant l'événement unique, cela ne fonctionnera que quand je sais que l'ID exacte, je ne peux pas l'exécuter pour chaque ID.

Existe-t-il un moyen de le faire pour chaque event_id individuel sans curseurs. J'ai vu une solution possible à l'utilisation d'un UDF malheureusement mon deuxième problème est le système d'horaires (CELCAT) crée une nouvelle base de données pour chaque année (je sais ne demande pas) alors je vais devoir faire le SQL dynamique à savoir la base de données des années à venir serait celcat200910, je crois que le SQL dynamique ne peut pas être exécuté dans les UDF.

S'il vous plaît rappelez-vous ceci est SQL Server 2000

+0

Sur les dispositions de DB: bruits rugueux. Oui, aucun SQL dynamique dans les fonctions définies par l'utilisateur n'est autorisé. Vous pourriez trouver de l'aide utile dans ce fil de discussion pour plusieurs travaux de DB: http://stackoverflow.com/questions/1037174/sql-use-statement-with-variable/1037961#1037961 ... Cependant, je pense que la meilleure solution serait Essayez de trouver un moyen de mettre les données dans une seule DB quelque part - mais cela peut être au-delà de votre compétence/appel du devoir. –

+0

Je mets la plupart des données dans une base de données séparée pour les données de présence et similaires. J'utilise une procédure de nuit pour peupler ce genre de choses, cependant cette requête particulière doit être en direct – PeteT

Répondre

1

Vous pouvez toujours utiliser une vue comme goodgai suggéré, mais au lieu de la rediriger vers une table, faites-la sélectionner les tables ensemble. Pourrait diviser l'année/mois en colonnes si ce n'est pas déjà fait et vous en avez besoin.

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

Vous pouvez créer une UDF pour calculer la chaîne, puis l'utiliser comme:

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

pourrait définir l'UDF comme:

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 
+0

renvoie varchar (4000) DECLARE @Tutors comme varchar (8000) tsk. tsk. isnull (@Tutors + '+', '') -> @Tutors + '+' n'est jamais nul – Coentje

+0

Corrigé le type de retour, mais la deuxième suggestion est fausse: @Tutors sera null pour la première ligne trouvée . – Andomar

0

Pour votre deuxième problème, utilisez une vue. Créez une vue pour chaque table d'intérêt dans la base de données celcat et utilisez les vues à la place. Lorsque la base de données passe à l'année suivante, il suffit de mettre à jour toutes les vues pour qu'elles pointent vers la nouvelle base de données.

Chaque requête dans le système utilisant la vue va maintenant adresser la bonne base de données.

+0

Je sais ce que vous dites mais habituellement les requêtes utilisent réellement plusieurs années de base de données. Je travaille dans un collège et celcat ainsi que la fréquentation des étudiants, ce qui est comparé à travers les lots. – PeteT

0
  • Puis-je demander pourquoi vous avez besoin de concaténer les noms sur le serveur? L'application cliente ne peut-elle pas le faire pour vous?

  • Si vous ne parvenez pas à adresser des tables dans d'autres bases de données, créez des vues avec des noms normalisés, un par table, qui sélectionnent simplement * dans chaque table. Vous pouvez écrire un SP qui crée automatiquement les vues, en vous laissant passer uniquement le nom de la base de données dans laquelle vous souhaitez définir toutes les vues. Les vues ne nuiront pas aux performances de manière significative. Comme vous utilisez une jointure à gauche pour CT_STAFF, cela me fait penser que le membre du personnel est peut-être manquant, auquel cas vous perdrez des données avec votre expression qui les concatène, car cela ne permet pas un personnel NULL name (il réinitialiserait la liste chaque fois qu'un nom de staff NULL était rencontré).

Voici une requête qui peut faire ce que vous avez besoin, mais il est un peu un hack:

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 

Assurez-vous de mettre assez de ces expressions Max() pour couvrir le plus grand nombre possible de personnel par événement.

Pour obtenir plus de données sur l'événement, ne le placez pas dans la table temporaire (cela le ralentira).Utilisez simplement cette grande requête comme sa propre table dérivée et revenez aux tables dont vous avez besoin.

0

J'ai fait un peu de développement de celcat au cours des derniers mois - c'est un peu un cauchemar, et je sympathise avec vous! Pour être honnête, dans cette situation, vous feriez mieux d'utiliser l'API Celcat (qui prend un peu de temps pour s'habituer, mais qui est assez puissante et qui a l'avantage que vos requêtes devraient être relativement sûres dans toutes les versions.)

J'ai créé une classe que j'ai utilisée pour sélectionner des versions de base de données spécifiques, etc. en créant une session spécifique à l'année scolaire que je voulais utiliser.

Dans l'API, il est également possible d'exécuter directement SQL si nécessaire.

Je sais que cela ne répond pas à votre question, mais j'espère que cela résout votre problème!

Questions connexes