MSSQL - Transpose
Geizhals » Forum » Programmierung » MSSQL - Transpose (33 Beiträge, 439 Mal gelesen) Top-100 | Fresh-100
Du bist nicht angemeldet. [ Login/Registrieren ]
MSSQL - Transpose
20.01.2011, 21:36:54
Hallo

Ich melde mich mal wieder mit einem Problem an dem ich derzeit scheitere. Ich habe folgende Datenstruktur:

Table: ARTIKEL
ARTIKEL     NAME
100-1001    Produkt1
100-1002    Produkt2

Table: ARTIKELLIEFERANT
ARTIKEL      LIEFERANTNAME       LIEFERANTBESTNR
100-1001     DiTech              0815
100-1001     E-Tec               4711
100-1001     Amazon              1112
100-1002     Teufel              A012
100-1002     Hofer               8273


Was ich nun gerne hätte ist folgendes:

ARTIKEL   NAME        LIEF1   LIEFNR1    LIEF2  LIEFNR2    LIEF3  LIEFNR3
100-1001  Produkt1    DiTech  0815       E-Tec  4711       Amazon 1112
100-1002  Produkt2    Teufel  A012       Hofer  8273       NULL   NULL


Dabei kommen maximal 3 Zeilen zu einem "Artikel" vor, sollten es mehr sein -> irrelevant.

Irgendwie komme ich bei der Fragestellung nicht ganz auf einen grünen Zweig. Versucht hätte ich es mittels PIVOT aber entweder es geht damit nicht oder ich habe mit zu dumm angestellt.

Achja, ich würde das ganze für viele Artikel in einer View benötigen, d.h. ich weiss nicht ob eine Lösung evtl. mittels Cursor hier sinnvoll wäre?

SQL Server wäre ein 2005er wenn das relevant ist :)

Danke mal im Voraus an die Spezialisten hier :)

Wenn der Sturm losbricht,
verstummen die Einen vor Schrecken,
und die Anderen breiten, einem Adler gleich, die Flügel aus
und schwingen sich empor.

Herzlichen Dank an Raydoo für die Fotos

Antworten PM Übersicht Chronologisch
 
Melden nicht möglich
...
Re(3): MSSQL - Transpose
21.01.2011, 12:08:05
ich auch net, drum sind meine lösungen meist eher improvisiert ;)

also die tabelle neu aufbaun (is nur so dahingeschrieben, muss net funktionieren, und ist sicher keine schöne lösung) (ok, eigentlich superhäßlich)

wenn die tabelle angelegt ist und neuetabelle heißt, gings in etwa so:

truncate table neuetabelle

insert into neuetabelle (artikel, [name]) select distinct artikel, [name] from artikel
update neuetabelle
set lief1 = (select top 1 lieferantname from artikellieferant where artikel  = neuetabelle.artikel),
set liefnr1 = (select lieferantbestnr from artikellieferant where artikel = neuetabelle.artikel and lieferantname = neuetabelle.lief1),
set lief2 = (select top 1 lieferantname from artikellieferant where artikel  = neuetabelle.artikel and not lieferantname = neuetabelle.lief1),
set liefnr2 = (select lieferantbestnr from artikellieferant where artikel = neuetabelle.artikel and lieferantname = neuetabelle.lief2),
set lief3 = (select top 1 lieferantname from artikellieferant where artikel  = neuetabelle.artikel and not lieferantname = neuetabelle.lief1 and not lieferantname = neuetabelle.lief2),
set liefnr3 = (select lieferantbestnr from artikellieferant where artikel = neuetabelle.artikel and lieferantname = neuetabelle.lief3)


danach hättest die table. ist aber wirklich sauhäßlich, aber zumindest hättest mal deine tabelle :)



Edit: für die top 1 queries müsstest ev. noch ein order by einbaun, damits deterministischer ist welche 3 ausgewählt werden (zb. order by lieferantname)

Bin mir jetzt net sicher ob der inhalt gleich aktualisiert wird zwecks der subqueries, oder ob dus in einzelne updates aufteilen müsstest

21.01.2011, 12:11 Uhr - Editiert von zeddicus, alte Version: hier
Antworten PM Übersicht Chronologisch Zum Vorgänger
 
Melden nicht möglich
.
Re: MSSQL - Transpose
21.01.2011, 17:05:56
Hallo !

meine Lösung dafür wäre es mittels min() und max() den niedriegsten bzw den höchsten Wert herauszuzuschen.

Du wirst nicht umhin kommen eine etwas wildere Schleifkonstruktion zu basteln.

Ich poste hier meinen Code für eine Funktion , den du gerne abwandeln kannst.
( es handelt sich hier um ein Beispiel wo es um Autoren zu einem Buch (identifiziert über die ISBN) geht)

-> die @ISBN wäre in deinem Fall die Artikel Nummer


CREATE FUNCTION Bib.udf_Autoren_pro_ISBN
(@ISBN NVARCHAR(13))
RETURNS nvarchar(256)
AS
BEGIN
  DECLARE @Autoren nvarchar(256)
  DECLARE @NeuerAutor nvarchar(64)
  DECLARE @laufvariable int = 0
  DECLARE @MinAutorID int
  DECLARE @MaxAutorID int

  -- ermittle min und max Autor ID für den gegebenen Buch Titel
  SELECT @MinAutorID = MIN(AutorID) FROM tbl_ISBNAutor WHERE ISBN = @ISBN
  SELECT @MaxAutorID = MAX(AutorID) FROM tbl_ISBNAutor WHERE ISBN = @ISBN

  -- initialisiere Variablen für die WHILE Schleife
  SET @laufvariable = @MinAutorID
  SET @Autoren = ''

  WHILE @laufvariable <= @MaxAutorID
    BEGIN
  
      SET @NeuerAutor = ''
      
      SELECT @NeuerAutor = LTRIM(ISNULL(a.Vorname,'') + ' ' + a.Nachname)
      FROM Bib.tbl_ISBNAutor AS i
      JOIN Bib.tbl_BuchAutor AS a ON i.AutorID = a.AutorID
      WHERE i.ISBN = @ISBN AND i.AutorID = @laufvariable
      
      SET @Autoren = @Autoren + @NeuerAutor
        
      SET @laufvariable = @laufvariable + 1
      
      -- Komma setzen wenn nicht der letzte Autor
      IF @laufvariable <= @MaxAutorID AND @NeuerAutor <> ''
        SET @Autoren = @Autoren + ', '
    END
  RETURN @Autoren
END





Antworten PM Übersicht Chronologisch Zum Vorgänger
 
Melden nicht möglich
.
Re: MSSQL - Transpose
23.01.2011, 01:02:20
direkt mit PIVOT wird das nicht hinhauen.

ich würde das ganze über einen zwischenschritt mittels einer view realisieren die dir so etwas wie eine Zeilen ID bezogen auf die Artikelnummer generiert. Das geht am einfachsten über RANK() OVER.

Konkret für dein Beispiel:

1. Schritt die View die dir das "ranking" erstellt:


SELECT     t0.artikel, t0.name, t1.lieferantname, t1.lieferantbestnr, rank() OVER (Partition BY T0.artikel ORDER BY t1.lieferantbestnr) AS liefid
FROM         dbo.[@artikel] AS t0 LEFT OUTER JOIN
                      dbo.[@artikellieferant] AS t1 ON t0.artikel = t1.artikel


ich habe diese als dbo.v_liefid abgespeichert. Das SQL Server Management Studio wird dir beim Ausführen direkt in der View einen Fehler ausgeben - funktioniert aber trotzdem ;)

Nun haben wir pro Artikel eine LieferantenID mit der wir weiterarbeiten können.

2. Schritt wäre nun deine gewünschte View damit das oben gewünschte Ergebnis ausgeben wird:


select t0.artikel, t0.name, t1.lieferantname, t1.lieferantbestnr, t2.lieferantname, t2.lieferantbestnr, t3.lieferantname, t3.lieferantbestnr
from dbo.[@artikel] as t0
left join dbo.v_liefid t1 on t0.artikel = t1.artikel and t1.liefid = 1
left join dbo.v_liefid t2 on t0.artikel = t2.artikel and t2.liefid = 2
left join dbo.v_liefid t3 on t0.artikel = t3.artikel and t3.liefid = 3


die Spalten musst halt dann noch mit AS so benennen wie du es gerne hättest. Diese Kosmetikaufgabe überlasse ich dir.



-----------------------------------
x-x-o
o-x-o
o-o-x ... and the winner is x
23.01.2011, 01:45 Uhr - Editiert von blitzfreak, alte Version: hier
Antworten PM Übersicht Chronologisch Zum Vorgänger
 
Melden nicht möglich
..
Re(2): MSSQL - Transpose
23.01.2011, 09:20:04
Hehe, MSSQL kennt zwar ein TOP, aber kein LIMIT ... das heisst nix mit limit 0,1

Jetzt gäbe es natürlich die Lösung das mit zwei verschachtelten Schleifen abzubilden, ist aber sicher alles andere als performant.

Ich habe mir jetzt mal angesehen wie mit den Daten umgegangen wird und bin zum Schluss gekommen dass an den Daten nur ganz selten (2,3 mal am Tag) was geändert wird, diese aber oft abgefragt werden.

Ich habe daher die Lösung von zeddicus genommen und meinen Anforderungen nach adaptiert. Nun wird nach einer Änderung der Daten mittels eines Triggers eine entsprechende Tabelle mit den gesamten Daten aktualisiert. Die Views greifen dann auf diese Zwischentabelle zurück. Das hat den Vorteil dass ich die Views sehr einfach halten kann, weil alle Daten im Prinzip schon in der Zwischentabelle drin sind und ich nur noch nach den entsprechenden Eigenschaften filtern muss.
Nachteil ist natürlich dass sich die Daten 2x in der Datenbank befinden, das wird jedoch dadurch gelöst dass diese Tabelle eben quasi "von der DB selbst" generiert wird. Der Client bekommt davon gar nichts mit.

Ich denke das ist eine Lösung mit der wir sicher die nächsten 5 Jahre überdauern können (und wahrscheinlich auch länger).

Daher danke an alle die hier mitgeholfen haben :)

Wenn der Sturm losbricht,
verstummen die Einen vor Schrecken,
und die Anderen breiten, einem Adler gleich, die Flügel aus
und schwingen sich empor.

Herzlichen Dank an Raydoo für die Fotos

Antworten PM Übersicht Chronologisch Zum Vorgänger
 
Melden nicht möglich
 

Dieses Forum ist eine frei zugängliche Diskussionsplattform.
Der Betreiber übernimmt keine Verantwortung für den Inhalt der Beiträge und behält sich das Recht vor, Beiträge mit rechtswidrigem oder anstößigem Inhalt zu löschen.
Datenschutzerklärung