2016-12-14 3 views
0

Wie kann ich diesen PostgreSQL-Code in SQL Server konvertieren?SQL Server array_agg (Master - Detail)

select 
    countries.title, 
    (select array_to_json(array_agg(row_to_json(t))) 
    from postcodes t 
    where t.country_id = countries.id) as codes 
from countries 

Mein erstes Problem ist, dass ich vollständige Master-Tabelle und mit jeder Zeile alle Details auswählen muss.

Länder:

id title 
1  SLO 
2  AUT 

POSTLEITZAHLEN:

id country_id code title 
1 1   1000 Lj 
2 1   2000 Mb 
3 2   22180 Vi 
4 2   22484 De 

Wunschergebnis:

1 SLO 1000;Lj|2000;MB 
2 AUT 22180;Vi|22484;De 

Nicht:

1 SLO 1000 Lj 
1 SLO 2000 Mb 
2 AUT 22180 Vi 
2 AUT 22484 De 

Die beste Lösung wäre FOR JSON verwenden, aber leider muss ich die Unterstützung für 2008 oder mindestens 2012

Mit LEFT JOIN alle Stammdaten zum Detail Zählung dupliziert, aber ich will nicht, dies zu tun. Noch schlimmer wäre es, alle Länder auszuwählen und dann wählen Sie auf post_codes für jedes Land in For-Schleife.

+0

SQL Server 2008 wird nicht mehr unterstützt. 2012 ist die früheste unterstützte Version, obwohl 2016 die offensichtliche Wahl ist, da Sie Columnstore-Indizes, Komprimierung, In-Memory-Tabellen, Partitionierung sogar in SQL Server Express und LocalDB (mit SP1) erhalten. Es kann billiger sein, als Code JSON Generation in T-SQL zu aktualisieren –

+1

Ich weiß, aber 500 Kunden zu überzeugen, dass sie neueren SQL gekauft haben, ist Mission unmöglich. Sie wollen, dass unser Produkt mit 2005 arbeiten würde. Wahnsinn, wenn Sie mich fragen. :) – Makla

+1

Auch wenn ihre Daten in die kostenlose Version von SQL Server Express passen könnten? Solche Conversions sind auf dem * Client * jedoch viel einfacher und sicherer. String Manipulation in der Datenbank ist teuer. Und was werden Sie tun, wenn Daten entweichen müssen? –

Antwort

3
select countries.title, 
     STUFF((select '|' + t.code + ';' + t.title 
       from postcodes t 
       where t.country_id = countries.id 
       FOR XML PATH('') 
      ),1,1,'') as codes 
    from countries 

- CAST t.code zu VARCHAR wenn es Nummer

0

versuchen Sie dies:

Select Main.COUNTRY_ID,c.title,Left(Main.POSTCODES,Len(Main.POSTCODES)-1) As "POSTCODES" 
From 
    (
     Select distinct ST2.COUNTRY_ID, 
      (
       Select ST1.CODE+';'+ST1.TITLE + '|' AS [text()] 
       From dbo.POSTCODES ST1 
       Where ST1.COUNTRY_ID = ST2.COUNTRY_ID 
       ORDER BY ST1.COUNTRY_ID 
       For XML PATH ('') 
      ) [POSTCODES] 
     From dbo.POSTCODES ST2 
    ) [Main] 

    inner join countries c on c.id=main.country_id 
0

XML PATH für Verkettung verwenden können die Komplexität des Codes erhöhen. Es ist besser, eine CLR aggregation function zu implementieren. Dann können Sie folgendes tun:

SELECT C.[id] 
     ,C.[title] 
     ,REPLACE([dbo].[Concatenate] (P.[code] + ';' + P.[title]), ',', '|') 
FROM @Countries C 
INNER JOIN @PostCodes P 
    ON C.[id] = p.[country_id] 
GROUP BY C.[id] 
     ,C.[title]; 

Sie können Ihre eigene Version des concatenate Aggregat erstellen - Sie das Trennzeichen angeben, die Reihenfolge etc. kann ich Ihnen Beispiele zeigen, wenn Sie möchten.

DECLARE @Countries TABLE 
(
    [id] TINYINT 
    ,[title] VARCHAR(12) 
); 

INSERT INTO @Countries ([id], [title]) 
VALUES (1, 'SLO') 
     ,(2, 'AUT'); 

DECLARE @PostCodes TABLE 
(
    [id] TINYINT 
    ,[country_id] TINYINT 
    ,[code] VARCHAR(12) 
    ,[title] VARCHAR(12) 
); 

INSERT INTO @PostCodes ([id], [country_id], [code], [title]) 
VALUES (1, 1, 1000, 'Lj') 
     ,(2, 1, 2000, 'Mb') 
     ,(3, 2, 22180, 'Vi') 
     ,(4, 2, 22484, 'De'); 

SELECT C.[id] 
     ,C.[title] 
     ,REPLACE([dbo].[Concatenate] (P.[code] + ';' + P.[title]), ',', '|') 
FROM @Countries C 
INNER JOIN @PostCodes P 
    ON C.[id] = p.[country_id] 
GROUP BY C.[id] 
     ,C.[title]; 

enter image description here

Verwandte Themen