none
Datensatz splitten RRS feed

  • Frage

  • Hallo,

    ich möchte gerne einen Datensatz in einzelne Teilen Splitten.

    Um das Problem genauer zu beschreiben. Es gibt einen Auftrag mit der Stückzahl n für jedes Teil soll nun eine Prüfung statt finden. Also möchte ich eine Tabelle mit n Zeilen um für jedes Teil Prüfung ok oder eben nicht ok eingetragen werden kann. Wie kann ich es über SQL lösen das solch eine Tabelle erstellt wird.

    Mittwoch, 17. Februar 2016 10:17

Antworten

  • Hallo Freerider,

    Du willst/must also basierend auf der Artikelnummer und der Stückzahl die Prüfungen persistent hinterlegen. Leider geht das nicht "in einem Schritt", da CTE (Common Table Expressions) nicht in einem CROSS APPLY verwendet warden können :(

    Aber mit der folgenden Lösung (basierend auf Deinem Code) sollte das gehen:

    -- Erstellen einer Inlinefunktion für die Rückgabe von
    -- n Datensätzen basierend auf einer Intervall-Variablen
    CREATE FUNCTION dbo.PruefAuftragListe (@Id INT, @Intervall INT)
    RETURNS TABLE
    AS
    RETURN
    (
    	WITH c
    	AS
    	(
    		SELECT	1			AS	RN,
    				artnr
    		FROM	dbo.gssauftrag
    		WHERE	id = @Id
    
    		UNION ALL
    
    		SELECT	RN + 1		AS	RN,
    				artnr
    		FROM	c
    		WHERE	RN <= @Intervall - 1
    	)
    	SELECT * FROM c
    );
    GO

    Die obige Funktion ist eine Inlinefunktion. Sie liefert mit Hilfe einer rekursiven Abfrage auf gssauftrag die Anzahl von Datensätzen für jede übergebene ID!

    Diese Funktion mußt Du nur noch in einem SELECT-Statement verwenden, dass die Daten persistent in Deine Hilfstabelle postet!

    SELECT	PAL.RN,
    		PAL.artnr
    FROM	dbo.gssauftrag AS G
    		CROSS APPLY dbo.PruefAuftragListe(G.Id, G.stkz) AS PAL
    GO

    Das obige Beispiel zeigt nur den SELECT-Aufruf. Aber er zeigt das generelle Verständnis für die Anwendung der zuvor erstellen Funktion. Mit Hilfe des SELECT-Statements solltest Du bereits erkennen, wie die Ausgabe zu verwenden ist.

    Ich vermute, dass sich in Deinem Design ein Fehler eingeschlichen hat, da Du eine [Auftrags_Id] einfügen möchtest. Im Result zeigst Du aber die Art_Nr. Da ich hier nicht sicher bin, was Du tatsächlich willst, kannst/must Du die Funktion entsprechend umgestalten.

    Weitere Literatur zu den behandelten Themen findest Du hier:

    recursive CTE: https://technet.microsoft.com/de-de/library/ms186243

    CROSS APPLY: https://technet.microsoft.com/de-de/library/ms175156.aspx


    MCM - SQL Server 2008
    MCSE - SQL Server 2012
    db Berater GmbH
    SQL Server Blog (german only)

    Mittwoch, 17. Februar 2016 13:58
  • Ich habe das mal etwas umgestellt, da die DDL-Statements nicht ganz stimmig waren. Außerdem benutze ich jetzt temporäre Tabellen zum testen.

    Das Ergebnis ist erst mal NULL.

    CREATE TABLE [#gssauftrag](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [artnr] [varchar](50) NOT NULL,
    [stkz] [int] NOT NULL,
     CONSTRAINT [PK_GSS_1] PRIMARY KEY CLUSTERED 
    (
    [id] ASC
    )
    );
    
    gO
    
    insert into #gssauftrag(artnr,stkz)
    values ('1234','30'),('2345','20'),('3456','10');
    
    
    CREATE TABLE #ergebnis(
    [id] [int] identity NOT NULL,
    [ergebnis] [varchar](15) NOT NULL,
     CONSTRAINT [PK_ergebnis] PRIMARY KEY NONCLUSTERED 
    (
    [id] ASC
    )
    );
    GO
    
    insert into #ergebnis (ergebnis)
    values ('ok'),('nacharbeit'),('ausschuss'),('pruefausnahme');
    
    CREATE TABLE #pruefauftrag(
    [id] [int] IDENTITY NOT NULL,
    [auftrags_id] [int] NOT NULL,
    [ergebnis_id] [int] NULL,
     CONSTRAINT [PK_pruefauftrag] PRIMARY KEY CLUSTERED 
    (
    [id] ASC
    )
    );
    
    GO
    
    With Nummern as
    (Select 1 as ID 
    UNION ALL
    Select ID + 1 as ID 
    from Nummern
    Where ID < 100)
    insert into #pruefauftrag(auftrags_id, ergebnis_id)
    Select g.artnr, NULL as ergebnis_ID
    from #gssauftrag g,
    Nummern n
    where n.ID <= g.stkz
    order by g.artnr, n.ID
    ; 
    
    
    Select id, auftrags_id, ergebnis_id
    from #pruefauftrag
    order by id;
    
    
    go
    drop table #gssauftrag;
    drop table #ergebnis;
    drop table #pruefauftrag;


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu

    Mittwoch, 17. Februar 2016 13:30

Alle Antworten

  • Hallo,

    wie sehen den die Quelldaten aus und wie genau soll das Ergebnis dann aussehen?


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Mittwoch, 17. Februar 2016 10:29
  • Die Quelldaten bestehen aus einer Tabelle mit den Spalten Auftrags_id, Artikelnummer und Stückzahl und das Ergebnis soll eine Tabelle pro Auftrags_id sein in der es eine Spalte Pruef_id, Auftrags_id und Ergebnis_id gibt diese Tabelle sollte dann der Stückzahl entsprechend viele Zeilen haben und wird über php und html im Browser dargestellt so dass der Prüfer die Möglichkeit hat per dropdown pro stück jeweils auszuwählen ob das Teil ok ist oder ob es einen Fehler hat
    Mittwoch, 17. Februar 2016 10:52
  • Die Daten kommen aus einer MS SQL 2008 Datenbank
    Mittwoch, 17. Februar 2016 10:54
  • Hi,

    poste bitte die Tabelle(n) als CREATE TABLE Statement, einige Beispieldaten als INSERT INTO Statement und dazu dann bitte das gewünschte Ergebnis.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Mittwoch, 17. Februar 2016 11:09
    Moderator
  • CREATE TABLE [dbo].[gssauftrag](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [artnr] [varchar](50) NOT NULL,
    [stkz] [int] NOT NULL,
     CONSTRAINT [PK_GSS_1] PRIMARY KEY CLUSTERED 
    (
    [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    insert into fes.dbo.gssauftrag(artnr,stkz)
    values ('1234','30'),('2345','20'),('3456','10');
    CREATE TABLE [dbo].[ergebnis](
    [id] [int] NOT NULL,
    [ergebnis] [varchar](15) NOT NULL,
     CONSTRAINT [PK_ergebnis] PRIMARY KEY NONCLUSTERED 
    (
    [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    insert into fes.dbo.ergebnis (ergebnis)
    values ('ok','nacharbeit','ausschuss','pruefausnahme');
    CREATE TABLE [dbo].[pruefauftrag](
    [id] [int] NOT NULL,
    [auftrags_id] [int] NOT NULL,
    [ergebnis_id] [int] NOT NULL,
     CONSTRAINT [PK_pruefauftrag] PRIMARY KEY CLUSTERED 
    (
    [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    ALTER TABLE [dbo].[pruefauftrag]  WITH CHECK ADD  CONSTRAINT [FK_pruefauftrag_gssauftrag] FOREIGN KEY([auftrags_id])
    REFERENCES [dbo].[gssauftrag] ([id])
    GO
    ALTER TABLE [dbo].[pruefauftrag] CHECK CONSTRAINT [FK_pruefauftrag_gssauftrag]
    GO
    Ergebnis soll dann eine Tabelle dieser art sein 
    pruef_id auftrags_id ergebnis_id
    1 1234
    2 1234
    3 1234
    4 1234
    5 1234
    6 1234
    7 1234
    8 1234
    9 1234
    10 1234
    11 1234
    12 1234
    13 1234
    14 1234
    15 1234
    16 1234
    17 1234
    18 1234
    19 1234
    20 1234
    21 1234
    22 1234
    23 1234
    24 1234
    25 1234
    26 1234
    27 1234
    28 1234
    29 1234

    30            1234

    Mittwoch, 17. Februar 2016 12:45
  • Das Ergebnis soll dann mit mit jedem weiteren Auftrag so ausshen

    pruef_id auftrags_id ergebnis_id
    1 1234
    2 1234
    3 1234
    4 1234
    5 1234
    6 1234
    7 1234
    8 1234
    9 1234
    10 1234
    11 1234
    12 1234
    13 1234
    14 1234
    15 1234
    16 1234
    17 1234
    18 1234
    19 1234
    20 1234
    21 1234
    22 1234
    23 1234
    24 1234
    25 1234
    26 1234
    27 1234
    28 1234
    29 1234
    30 1234
    31 2345
    32 2345
    33 2345
    34 2345
    35 2345
    36 2345
    37 2345
    38 2345
    39 2345
    40 2345
    41 2345
    42 2345
    43 2345
    44 2345
    45 2345
    46 2345
    47 2345
    48 2345
    49 2345
    50 3456
    51 3456
    52 3456
    53 3456
    54 3456
    55 3456
    56 3456
    57 3456
    58 3456
    59 3456
    60 3456

    Mittwoch, 17. Februar 2016 13:05
  • Ich habe das mal etwas umgestellt, da die DDL-Statements nicht ganz stimmig waren. Außerdem benutze ich jetzt temporäre Tabellen zum testen.

    Das Ergebnis ist erst mal NULL.

    CREATE TABLE [#gssauftrag](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [artnr] [varchar](50) NOT NULL,
    [stkz] [int] NOT NULL,
     CONSTRAINT [PK_GSS_1] PRIMARY KEY CLUSTERED 
    (
    [id] ASC
    )
    );
    
    gO
    
    insert into #gssauftrag(artnr,stkz)
    values ('1234','30'),('2345','20'),('3456','10');
    
    
    CREATE TABLE #ergebnis(
    [id] [int] identity NOT NULL,
    [ergebnis] [varchar](15) NOT NULL,
     CONSTRAINT [PK_ergebnis] PRIMARY KEY NONCLUSTERED 
    (
    [id] ASC
    )
    );
    GO
    
    insert into #ergebnis (ergebnis)
    values ('ok'),('nacharbeit'),('ausschuss'),('pruefausnahme');
    
    CREATE TABLE #pruefauftrag(
    [id] [int] IDENTITY NOT NULL,
    [auftrags_id] [int] NOT NULL,
    [ergebnis_id] [int] NULL,
     CONSTRAINT [PK_pruefauftrag] PRIMARY KEY CLUSTERED 
    (
    [id] ASC
    )
    );
    
    GO
    
    With Nummern as
    (Select 1 as ID 
    UNION ALL
    Select ID + 1 as ID 
    from Nummern
    Where ID < 100)
    insert into #pruefauftrag(auftrags_id, ergebnis_id)
    Select g.artnr, NULL as ergebnis_ID
    from #gssauftrag g,
    Nummern n
    where n.ID <= g.stkz
    order by g.artnr, n.ID
    ; 
    
    
    Select id, auftrags_id, ergebnis_id
    from #pruefauftrag
    order by id;
    
    
    go
    drop table #gssauftrag;
    drop table #ergebnis;
    drop table #pruefauftrag;


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu

    Mittwoch, 17. Februar 2016 13:30
  • Hallo Freerider,

    Du willst/must also basierend auf der Artikelnummer und der Stückzahl die Prüfungen persistent hinterlegen. Leider geht das nicht "in einem Schritt", da CTE (Common Table Expressions) nicht in einem CROSS APPLY verwendet warden können :(

    Aber mit der folgenden Lösung (basierend auf Deinem Code) sollte das gehen:

    -- Erstellen einer Inlinefunktion für die Rückgabe von
    -- n Datensätzen basierend auf einer Intervall-Variablen
    CREATE FUNCTION dbo.PruefAuftragListe (@Id INT, @Intervall INT)
    RETURNS TABLE
    AS
    RETURN
    (
    	WITH c
    	AS
    	(
    		SELECT	1			AS	RN,
    				artnr
    		FROM	dbo.gssauftrag
    		WHERE	id = @Id
    
    		UNION ALL
    
    		SELECT	RN + 1		AS	RN,
    				artnr
    		FROM	c
    		WHERE	RN <= @Intervall - 1
    	)
    	SELECT * FROM c
    );
    GO

    Die obige Funktion ist eine Inlinefunktion. Sie liefert mit Hilfe einer rekursiven Abfrage auf gssauftrag die Anzahl von Datensätzen für jede übergebene ID!

    Diese Funktion mußt Du nur noch in einem SELECT-Statement verwenden, dass die Daten persistent in Deine Hilfstabelle postet!

    SELECT	PAL.RN,
    		PAL.artnr
    FROM	dbo.gssauftrag AS G
    		CROSS APPLY dbo.PruefAuftragListe(G.Id, G.stkz) AS PAL
    GO

    Das obige Beispiel zeigt nur den SELECT-Aufruf. Aber er zeigt das generelle Verständnis für die Anwendung der zuvor erstellen Funktion. Mit Hilfe des SELECT-Statements solltest Du bereits erkennen, wie die Ausgabe zu verwenden ist.

    Ich vermute, dass sich in Deinem Design ein Fehler eingeschlichen hat, da Du eine [Auftrags_Id] einfügen möchtest. Im Result zeigst Du aber die Art_Nr. Da ich hier nicht sicher bin, was Du tatsächlich willst, kannst/must Du die Funktion entsprechend umgestalten.

    Weitere Literatur zu den behandelten Themen findest Du hier:

    recursive CTE: https://technet.microsoft.com/de-de/library/ms186243

    CROSS APPLY: https://technet.microsoft.com/de-de/library/ms175156.aspx


    MCM - SQL Server 2008
    MCSE - SQL Server 2012
    db Berater GmbH
    SQL Server Blog (german only)

    Mittwoch, 17. Februar 2016 13:58
  • Vielen Dank für die unglaublich schnelle und gute Hilfe und auch noch einen schönen Tag
    Mittwoch, 17. Februar 2016 14:03
  • Die Ausgangstabelle enthält eigentlich noch mehr Spalten jedoch ist durch die Auftrags_id und die Stückzahl eigentlich alles notwendige an Informationen abgedeckt um die Möglichkeit zu haben  für jedes Teil die durchgeführte Prüfung zu dokumentieren. Denke ich zumindest, ich kann aber auch falsch liegen. Ich teste die Lösung mit der Inline Funktion einfach auch noch und schaue was sich am besten einbinden lässt. 

    Danke für die echt super Hilfe. Einen schönen Tag noch

    Mittwoch, 17. Februar 2016 14:22
  • Ah ok, ich weiß was sie meinen, ja ist richtig ansonsten würde es nicht automatisch für den nächsten Auftrag auch funktionieren
    Mittwoch, 17. Februar 2016 14:31
  • Die Lösung ist Perfekt, danke noch mal :D
    Mittwoch, 17. Februar 2016 14:49
  • Ich habe nochmal eine Frage bezüglich dieser Abfrage.

    -- Erstellen einer Inlinefunktion für die Rückgabe von -- n Datensätzen basierend auf einer Intervall-Variablen CREATE FUNCTION dbo.PruefAuftragListe (@Id INT, @Intervall INT) RETURNS TABLE AS RETURN ( WITH c AS ( SELECT 1 AS RN, artnr FROM dbo.gssauftrag WHERE id = @Id UNION ALL SELECT RN + 1 AS RN, artnr FROM c WHERE RN <= @Intervall - 1 ) SELECT * FROM c ); GO

    Wie muss ich die Abfrage ändern um lediglich für eine bestimmte Artikelnummer die Tabelle für die einzelnen Prüfungen zu erhalten.

    Montag, 14. März 2016 12:16
  • Hallo!

    1.) Solltest Du nicht in einem beantworteten Thread neue Fragen stellen. Das reduziert die Wahrscheinlichkeit auf eine Antwort deutlich.

    2.) Wirst Du wahrscheinlich beim Anker-Element die Where-Bedingung erweiterung müssen. Also in der Art:

    WHERE	id = @Id
    and ID in (11223344, 55667788)
    Damit werden nur noch für die beiden Artikelnummern die Listen erzeugt.


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu

    Montag, 14. März 2016 14:13