J'ai une simple requête sur une table, qui renvoie des résultats comme les suivants:
id concatenation 2702 5,16,17,40:31,14,3,1 2703 23,23,34:4,5,6 2704 1:14
7 Réponses :
Voici une solution: update: strong> une autre approche p>
Quelle version de Sybase utilisez-vous? Je ne peux pas sembler avoir "pour XML ..." pour travailler. Ma version est ASE 12.5.4
Quant à la deuxième solution, n'est-ce pas l'oracle?
J'ai fait ces solutions avec MSSQL, mais la seconde devrait travailler avec Sybase, autant que j'ai trouvé qu'il soutient des expressions de table communes
@Oleg, je pense que nous sommes tombés dans les anciennes "extensions incompatibles" ici :)
@dsm, peut-être, désolé si je vous ai mal guidé.
Le meilleur que je puisse penser maintenant est le prochain: mais le résultat est un peu différent de celui que vous avez dactylographié ... !!! P> P> P> P> P> P> P> P> P> >
Il est trop simple, mais il n'a pas besoin d'sql supplémentaire et difficile de codage
Veuillez formater votre réponse en utilisant le bloc "Code" pour une lecture plus facile.
J'ai essayé de reformater votre code sans chance. Votre solution fonctionne effectivement pour cet exemple particulier, mais supposons maintenant que nous voulons de la même manière pour plusieurs identifiants ou répétez ID_TYPES
Une autre approche qui fonctionne sur Sybase ASE 12.5.4. La table doit avoir un indice en cluster sur ID, afin que cela fonctionne. En supposant que le nom de la table soit Mytable:
declare @strNew varchar(10), @strOld varchar(10), @str1 varchar(1000), @str2 varchar(1000) set @str1 = NULL, @str2 = NULL, @strNew = NULL, @strOld = NULL UPDATE MYTABLE SET @strNew = convert(varchar,id) , @str1 = case when @strNew = @strOld then @str1 + convert(varchar,id_type) + "," else @str1 + '$' + @strNew + '$' + convert(varchar,id_type) + "," end , @str2 = case when @strNew = @strOld then @str2 + convert(varchar,id_ref) + "," else @str2 + '$' + @strNew + '$' + convert(varchar,id_ref) + "," end , @strOld = convert(varchar,id) select id, substring(@str1,charindex("$" + convert(varchar,id) + "$",@str1) + len("$" + convert(varchar,id) + "$"), case when charindex(",$",substring(@str1,charindex("$" + convert(varchar,id) + "$",@str1) + len("$" + convert(varchar,id) + "$") + 1,len(@str1))) = 0 then len(@str1) - (charindex("$" + convert(varchar,id) + "$",@str1) + len("$" + convert(varchar,id) + "$")) else charindex(",$",substring(@str1,charindex("$" + convert(varchar,id) + "$",@str1) + len("$" + convert(varchar,id) + "$") + 1,len(@str1))) end ) + ':' + substring(@str2,charindex("$" + convert(varchar,id) + "$",@str2) + len("$" + convert(varchar,id) + "$"), case when charindex(",$",substring(@str2,charindex("$" + convert(varchar,id) + "$",@str2) + len("$" + convert(varchar,id) + "$") + 1,len(@str2))) = 0 then len(@str2) - (charindex("$" + convert(varchar,id) + "$",@str2) + len("$" + convert(varchar,id) + "$")) else charindex(",$",substring(@str2,charindex("$" + convert(varchar,id) + "$",@str2) + len("$" + convert(varchar,id) + "$") + 1,len(@str2))) end ) as concatenation from MYTABLE group by id
@DSM ajoutez les éléments suivants après la déclaration de mise à jour pour voir les chaînes qu'il crée: impression "% 1!:% 2!", @ str1, @ str2 code>. L'instruction SELECT qui suit, extrait des sous-chaînes appropriées de ces chaînes en fonction de la valeur de
ID code>. Les précautions doivent être prises pour compter la bonne longueur. L'instruction code> code> est nécessaire car une fois la dernière sous-chaîne, il n'y a pas de
, $ code> plus, ce qui indique la fin de la sous-chaîne. J'espère que cela pourra aider.
J'ai testé cela et cela fonctionne bien pour une petite myTable, mais une table arbitrairement importante le brise. Résultats comme les suivants commencent à montrer: 62126 16,17,6,6,6,22 $: 11,5,11,28,1 $
@DSM Oui, je sais que cela ne peut pas être utilisé pour une grande myTable car la solution est limitée par la longueur de @ STR1, @ STR2 qui ne peut pas être plus grand que Varcharate (16384). C'est pourquoi j'ai proposé une autre solution.
Je n'ai pas de serveur Sybase pour tester, mais lire les documents en ligne, il apparaît que des expressions de table communes sont prises en charge. Je n'étais pas sûr à propos de Row_Number, tel qu'utilisé dans d'autres solutions, voici une solution qui n'utilise pas cela.
Je crois que Sybase utilise || Pour la concaténation à la chaîne, bien que les docs que j'ai lusent mentionne que "+" puisse également être utilisé, alors j'ai utilisé cela. S'il vous plaît changer selon le cas. P>
J'ai commenté la requête pour essayer d'expliquer ce qui se passe. P>
La requête concaténe toutes les valeurs ID_TYPE et ID_RF avec le même ID, dans l'augmentation de la valeur ID_TYPE 'Commande. P>
/* a common table expression is used to concatenate the values, one by one */ WITH ConcatYourTable([id], /* the id of rows being concatenated */ concat_id_type, /* concatenated id_type so far */ concat_id_ref, /* concatenated id_ref so far */ last_id_type, /* the last id_type added */ remain) /* how many more values are there to concatenate? */ AS ( /* start with the lowest id_type value for some id */ SELECT id, id_type, id_ref, id_type, /* id_type was concatentated (it's presently the only value) */ (SELECT COUNT(*) FROM YourTable f2 WHERE f2.id=f.id)-1 /* how many more values to concatenate -1 because we've added one already */ FROM YourTable f WHERE NOT EXISTS /* start with the lowest value - ensure there are no other values lower. */ (SELECT 1 FROM YourTable f2 WHERE f2.id=f.id AND f2.id_type<f.id_type) UNION ALL /* concatenate higher values of id_type for the same id */ SELECT f.id, c.id_type + ',' + f.id_type, /* add the new id_type value to the current list */ c.id_ref + ',' + f.id_ref, /* add the new id_ref value to the current list */ f.id_type, /* the last value added - ensured subsequent added values are greater */ c.remain-1 /* one less value to add */ FROM ConcatYourTable c /* take what we have concatenated so far */ INNER JOIN YourTable f /* add another row with the same id, and > id_type */ ON f.id = c.id AND f.id_type > c.last_id_type /* we really want the next highest id_type, not just one that is greater */ WHERE NOT EXISTS (SELECT 1 FROM YourTable f2 WHERE f2.id=f.id AND f2.id_type<f.id_type AND f2.id_type>c.last_id_type) ) /* Select the rows where all values for and id were concatenated (remain=0) */ /* Concatenate the cumulated id_type and id_ref fields to format id_type values:id_ref values*/ SELECT id, id_type+':'+id_ref FROM ConcatYourTable WHERE remain=0
Ceci n'est pas valide SYBASE SYNTAX. Merci quand même :-)
J'ai dû consulter le mauvais manuel. Connaissez-vous-vous où trouver la syntaxe en ligne? Si oui, je vais réécrire la requête le cas échéant.
Étant donné qu'il est assez difficile de faire ce fait à Sybase à l'aide d'une instruction SELECT, je suggérerais un pendant code> comme suit. Tandis que les boucles sont préférées sur des curseurs pour être beaucoup plus rapide. En supposant que le nom de la table soit MYTABLE:
CREATE TABLE #temp
(
aa numeric(5,0) identity,
id int not null,
id_type int not null,
id_ref int not null
)
CREATE TABLE #results
(
id int not null,
concatenation varchar(1000) not null,
)
insert into #temp
select id, id_type, id_ref from MYTABLE order by id
declare @aa int, @maxaa int, @idOld int, @idNew int
declare @str1 varchar(1000), @str2 varchar(1000), @j int
set @aa = 1
set @maxaa = (select max(aa) from #temp)
set @idNew = (select id from #temp where aa = 1)
, @idOld = @idNew
set @str1 = ':'
while @aa <= @maxaa
begin
set @idNew = (select id from #temp where aa = @aa)
IF @idNew = @idOld
BEGIN
set @str2 = (select convert(varchar,id_type) + ':' + convert(varchar,id_ref) from #temp where aa = @aa)
set @j = (select charindex(':',@str2))
set @str1 = str_replace(@str1, ':', substring(@str2,1,@j - 1) + ',:') + right(@str2,len(@str2) - @j) + ','
IF @aa = @maxaa
insert into #results (id, concatenation)
VALUES (@idOld, left(str_replace(@str1, ',:', ':'),len(@str1) - 2) )
END
ELSE
BEGIN
insert into #results (id, concatenation)
VALUES (@idOld, left(str_replace(@str1, ',:', ':'),len(@str1) - 2) )
set @str1 = ':'
set @str2 = (select convert(varchar,id_type) + ':' + convert(varchar,id_ref) from #temp where aa = @aa)
set @j = (select charindex(':',@str2))
set @str1 = str_replace(@str1, ':', substring(@str2,1,@j - 1) + ',:') + right(@str2,len(@str2) - @j) + ','
IF @aa = @maxaa
insert into #results (id, concatenation)
VALUES (@idNew, left(str_replace(@str1, ',:', ':'),len(@str1) - 2) )
END
set @idOld = @idNew
set @aa = @aa+1
end
select * from #results
Cette approche prend considérablement plus longtemps que le curseur que j'utilise actuellement avec les données réelles
+1 pour générer des résultats corrects. Je laisserai la question ouverte jusqu'à ce que j'ai fini d'évaluer toutes les autres réponses
@DSM Une raison évidente du succès de la performance est la récréation de la table initiale (comme #temp). Vous pouvez omettre l'étape de la récréation de la table si votre table réelle a une colonne d'identité ou une autre pièce d'identité unique, et vous pouvez donc utiliser cette colonne comme compteur à la place.
La table #TEpp est peuplée très rapidement. Le retard survient pendant la boucle tandis que.
OK, pardonnez-moi si je manque quelque chose de crucial ici parce que je ne connais pas la première chose à propos de Sybase. Mais dans MySQL, cela est absurdement simple, donc je pensais que cela ne pouvait pas être aussi mauvais que les réponses jusqu'à présent. Donc, tirer de la documentation qui peut être pertinente ou non:
SELECT id, LIST(id_type) + ":" + LIST(id_ref) AS concatentation
Pour ma propre édification, l'esprit expliquant qu'en est-il de cela ne fonctionne pas?
Ah, il semble que c'est une question de versions différentes: "Sybase Adaptive Server Anywhere (mais pas Adaptive Server Enterprise) a cette fonction d'agrégat non soignée, bien que propriétaire, non standard appelée liste ()."
Utilisez la fonction de niveau de ligne.
Votre requête: p> fonction: p>
Édité les balises Un bit "pivot" est le terme le plus couramment utilisé ici, pourrait obtenir les personnes appropriées en regardant la question si vous avez mis à jour pour l'utiliser, en particulier dans le titre.