Złączenie wielu rekordów z kilku kolumn w jeden

0

Witam, mam problem z uzyskaniem prawidłowego wyniku w zapytaniu SQL.
Wynik widoczny w załączniku numer jeden.
Chciałabym aby trzy widoczne wiersze złączyły się w jeden, a tym samym uniknąć kolumn z wartościami NULL.
Oczekiwany wynik:

16 | Abonament RTK_ECC076256 | REBY | 1 | 1680,96 | 110 | 110 | NIE |

Generalnie zapytanie jest dość długie, nie wiem, który fragment należy umieścić aby spojrzenie na problem było klarowniejsze.
Dlatego też, wkleję całe zapytanie do bazy.

SELECT DISTINCT 
        WSZYSTKO.PRODUKT AS TOWAR ,
        WSZYSTKO.MAGAZYN_ID AS MAGAZYN ,
        WSZYSTKO.ilość ,
        WSZYSTKO.netto ,
        WSZYSTKO.ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU ,
        WSZYSTKO.ILOSC_DNI_NA_MAGAZYNIE ,
        WSZYSTKO.CZY_ARCHIWALNY
FROM    ( SELECT  DISTINCT  TABELA.PRODUKT_INDEKS ,
                    TABELA.PRODUKT ,
                    TABELA.MAGAZYN_ID ,
                    TABELA.ilość ,
                    TABELA.netto ,
                    NULL AS ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU ,
                    NULL AS ILOSC_DNI_NA_MAGAZYNIE ,
                    TABELA.CZY_ARCHIWALNY
          FROM      ( SELECT  DISTINCT  m.PRODUKT_INDEKS AS PRODUKT_INDEKS ,
                                produkt.PRODUKT AS PRODUKT ,
                                m.MAGAZYN_ID AS MAGAZYN_ID ,
                                SUM(m.ZS_Ilość) AS ilość ,
                                SUM(m.ZS_Netto) AS netto ,
                                produkt.CZY_ARCHIWALNY
                      FROM      CSTMP_B_MAGAZYNY AS m
                                LEFT OUTER JOIN CSTMP_B_MAGAZYN AS mag ON mag.MAGAZYN_ID = m.MAGAZYN_ID
                                LEFT OUTER JOIN CSTMP_B_PRODUKT AS produkt ON produkt.PRODUKT_INDEKS = m.PRODUKT_INDEKS
                      WHERE     ( m.BRANŻA_ID = 'E' )
                      GROUP BY  m.PRODUKT_INDEKS ,
                                produkt.PRODUKT ,
                                m.MAGAZYN_ID ,
                                produkt.CZY_ARCHIWALNY
                      HAVING    ( SUM(m.ZS_Ilość) <> 0 )
                                AND ( SUM(m.ZS_Netto) <> 0 )
                    ) AS TABELA
          GROUP BY  TABELA.PRODUKT_INDEKS ,
                    TABELA.PRODUKT ,
                    TABELA.MAGAZYN_ID ,
                    TABELA.ilość ,
                    TABELA.netto ,
                    TABELA.CZY_ARCHIWALNY
          UNION all
          SELECT    DISTINCT  PRODUKT_INDEKS ,
                    PRODUKT ,
                    NULL AS MAGAZYN_ID ,
                    NULL AS ILOŚĆ ,
                    NULL AS NETTO ,
                    ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU ,
                    NULL AS ILOSC_DNI_NA_MAGAZYNIE ,
                    NULL AS CZY_ARCHIWALNY
          FROM      ( SELECT   DISTINCT t1a.PRODUKT_INDEKS ,
                                t2.PRODUKT ,
                                t1a.dni AS ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU
                      FROM      ( SELECT DISTINCT   PRODUKT_INDEKS ,
                                            MIN(Dni) AS dni
                                  FROM      ( SELECT DISTINCT   s.PRODUKT_INDEKS ,
                                                        pro.PRODUKT ,
                                                        DATEDIFF(d, s.DATA_DOK, GETDATE()) AS Dni
                                              FROM      CSTMP_B_SPRZEDAŻ AS s
                                                        INNER JOIN CSTMP_B_PRODUKT
                                                        AS pro ON pro.PRODUKT_INDEKS = s.PRODUKT_INDEKS
                                              WHERE     ( s.BRANŻA_ID = 'E' )
                                                        AND ( s.DATA_SPRZEDAŻY > 2016
                                                              - 12 - 31 )
                                            ) AS t1
                                  GROUP BY  PRODUKT_INDEKS
                                ) AS t1a
                                INNER JOIN ( SELECT DISTINCT s.PRODUKT_INDEKS ,
                                                    pro.PRODUKT ,
                                                    DATEDIFF(d, s.DATA_DOK, GETDATE()) AS Dni
                                             FROM   CSTMP_B_SPRZEDAŻ AS s
                                                    INNER JOIN CSTMP_B_PRODUKT
                                                    AS pro ON pro.PRODUKT_INDEKS = s.PRODUKT_INDEKS
                                             WHERE  ( s.BRANŻA_ID = 'E' )
                                                    AND ( s.DATA_SPRZEDAŻY > 2016
                                                          - 12 - 31 )
                                           ) AS t2 ON t2.Dni = t1a.dni
                                                      AND t2.PRODUKT_INDEKS = t1a.PRODUKT_INDEKS
                    ) AS TABLICA2
          GROUP BY  TABLICA2.PRODUKT_INDEKS ,
                    TABLICA2.PRODUKT ,
                    TABLICA2.ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU
          UNION ALL
          SELECT    DISTINCT  PRODUKT_INDEKS ,
                    PRODUKT ,
                    NULL AS MAGAZYN_ID ,
                    NULL AS ILOŚĆ ,
                    NULL AS NETTO ,
                    NULL AS DNI_OD_OSTATNIEGO_DOKUMENTU ,
                    ILOSC_DNI_NA_MAGAZYNIE ,
                    NULL AS CZY_ARCHIWALNY
          FROM      ( SELECT DISTINCT   tab1a.PRODUKT_INDEKS ,
                                tab2.PRODUKT ,
                                tab1a.Dni AS ILOSC_DNI_NA_MAGAZYNIE
                      FROM      ( SELECT  DISTINCT  PRODUKT_INDEKS ,
                                            MIN(Dni) AS Dni
                                  FROM      ( SELECT  DISTINCT  M.PRODUKT_INDEKS ,
                                                        pro.PRODUKT ,
                                                        DATEDIFF(d, M.DATA, GETDATE()) AS Dni
                                              FROM      CSTMP_B_MAGAZYNY AS M
                                                        INNER JOIN CSTMP_B_PRODUKT
                                                        AS pro ON pro.PRODUKT_INDEKS = M.PRODUKT_INDEKS
                                              WHERE     ( M.BRANŻA_ID = 'E' )
                                                        AND ( M.DATA > 2016
                                                              - 12 - 31 )
                                            ) AS tab1
                                  GROUP BY  PRODUKT_INDEKS
                                ) AS tab1a
                                INNER JOIN ( SELECT DISTINCT M.PRODUKT_INDEKS ,
                                                    pro.PRODUKT ,
                                                   DATEDIFF(d, M.DATA, GETDATE()) AS Dni
                                             FROM   CSTMP_B_MAGAZYNY AS M
                                                    INNER JOIN CSTMP_B_PRODUKT
                                                    AS pro ON pro.PRODUKT_INDEKS = M.PRODUKT_INDEKS
                                             WHERE  ( M.BRANŻA_ID = 'E' )
                                                    AND ( M.DATA > 2016 - 12
                                                          - 31 )
                                           ) AS tab2 ON tab2.Dni = tab1a.Dni
                                                        AND tab2.PRODUKT_INDEKS = tab1a.PRODUKT_INDEKS
                    ) AS TABELA3
          GROUP BY  TABELA3.PRODUKT_INDEKS ,
                    TABELA3.PRODUKT ,
                    TABELA3.ILOSC_DNI_NA_MAGAZYNIE
        ) AS WSZYSTKO
GROUP BY WSZYSTKO.ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU ,
        WSZYSTKO.PRODUKT_INDEKS ,
        WSZYSTKO.PRODUKT ,
        WSZYSTKO.MAGAZYN_ID ,
        WSZYSTKO.ilość ,
        WSZYSTKO.netto ,
        WSZYSTKO.ILOSC_DNI_NA_MAGAZYNIE ,
        WSZYSTKO.CZY_ARCHIWALNY
ORDER BY WSZYSTKO.PRODUKT

Pozdrawiam serdecznie,
Wlina

0

Jak dobrze rozumiem, masz 3 selekty i potrzebujesz otrzymać z nich jeden wiersz? Nie da się tego osiągnąć po przez union all. Musisz te trzy selecty połączyć w Join. Poza tym strasznie dużo masz DISTINCTów co spowoduje znaczny spadek wydajności.

0

@Tomek Pycia: Tylko teraz nie bardzo wiem gdzie teraz wstawic sugerowane JOINy??
Przepraszam, dopiero sie ucze.

0

A na jakiej to bazie robisz? Te JOINy trzeba wstawić tak, jak masz w tych podzapytaniach. To projekt na zaliczenie? Mam wrażenie, że to zapytanie jest strasznie skomplikowanie, a takie nie musi być, ale nie wiem, jaka jest baza i jakie są wymagania dla tego zapytania, żeby coś więcej powiedzieć. Nie znam też bazy, która łyknie datę w takiej postaci:

AND ( s.DATA_SPRZEDAŻY > 2016 - 12 - 31 
2

Ale sieka...

Masz 3 uniony z czego pierwszy jeszcze rozumiem to dwa pozostale są zagadką, dlaczego joinujesz się po tym samym: w drugim unionie podzapytanie t1a i 1t2 i analogiczne zapytanie z 3 joina tab1a i tab2?

Odpowiem tak, mimo odpowiedzi @Tomek Pycia można połączyć te wiersze wjeden, nieelegancko ale da się:

select
    PRODUKT_INDEKS ,
    PRODUKT ,
    max(MAGAZYN_ID) MAGAZYN_ID ,
    max(ilość) AS ILOŚĆ ,
    max(netto) AS NETTO ,
    max(DNI_OD_OSTATNIEGO_DOKUMENTU) AS DNI_OD_OSTATNIEGO_DOKUMENTU ,
    max( ILOSC_DNI_NA_MAGAZYNIE) as  ILOSC_DNI_NA_MAGAZYNIE ,
    max(CZY_ARCHIWALNY)  AS CZY_ARCHIWALNY
from
    (
    --cale to Twoje wielkie zapytanie
    ) dt
group by 
    PRODUKT_INDEKS ,
    PRODUKT 

Można też trochę uprościć to co napisałąs i zrobić mniej więcej tak:

SELECT 
       m.PRODUKT_INDEKS AS PRODUKT_INDEKS,
       produkt.PRODUKT AS PRODUKT,
       m.MAGAZYN_ID AS MAGAZYN_ID,
       SUM(m.ZS_Ilość) AS ilość,
       SUM(m.ZS_Netto) AS netto,
	  max(DATEDIFF(d, s.DATA_DOK, GETDATE())) as ILOSC_DNI_OD_OSTATNIEGO_DOKUMENTU,
	  max(case when m.data >'2016-12-31' and M.BRANŻA_ID = 'E' then DATEDIFF(d, M.DATA, GETDATE()) else null end) ILOSC_DNI_NA_MAGAZYNIE
       produkt.CZY_ARCHIWALNY
FROM 
    CSTMP_B_MAGAZYNY AS m
     LEFT OUTER JOIN CSTMP_B_MAGAZYN AS mag ON mag.MAGAZYN_ID = m.MAGAZYN_ID
     LEFT OUTER JOIN CSTMP_B_PRODUKT AS produkt ON produkt.PRODUKT_INDEKS = m.PRODUKT_INDEKS
	LEFT JOIN	CSTMP_B_SPRZEDAŻ	  AS s on produkt.PRODUKT_INDEKS = s.PRODUKT_INDEKS  
								and s.BRANŻA_ID = 'E'
								AND s.DATA_SPRZEDAŻY > '2016-12-31'
GROUP BY m.PRODUKT_INDEKS,
         produkt.PRODUKT,
         m.MAGAZYN_ID,
         produkt.CZY_ARCHIWALNY
HAVING
    (SUM(m.ZS_Ilość) <> 0)
      AND (SUM(m.ZS_Netto) <> 0);
0

Nie mam jakoś weny na analizowanie całości, ale można użyć funkcji analitycznych.

Dla oracla wyglądałoby to tak:

with prepared_data as ( 
	/* Twoje zapytanie  */ 
)
select 
	abonament,
	max(attr1) keep (dense_rank last order by case when attr1 is null then 1 else 2 end) as attr1,
	max(attr2) keep (dense_rank last order by case when attr1 is null then 1 else 2 end) as attr2
from 
	prepared_data
group by 
	abonament;

Logika następująca:

  1. Twoje zapytanie wrzucamy do osobnego bloku i nazywamy prepared_data
  2. Agregujemy po abonamencie (group by abonament)
  3. Per abonament wybieramy maksymalną wartość atrybutu, ale według rangi, którą sami określamy
0

@Tomek Pycia: Na Microsoft SQL Server. Coś kombinuję, ale nadal nic. Jestem na stażu w firmie i jest to moje zadanie. Data akurat jest ok.
Niemniej jednak, dziękuję Ci serdecznie za odpowiedź :)

@Panczo: Pętle z t1 i t1a oraz tab1 i tab1a powstały na początku tej wielkiej plątaniny i miały za zadanie sprawdzić prawdziwość zapytania.
Przez group by działa.Wynik zapytania jest lepszy, jednak nadal zbyt dużo NULL, mimo iż przy nowym zapytaniu sprawdzającym np. Magazyn_ID się pojawia.

Sprawdziłam Twoje zapytanie, mieli strasznie długo, bo aż 10 min. Ale działa - wynik zapytania zdecydowanie lepszy od mojego.
Dziękuję uprzejmie za odpowiedź :)

0

Ewelina pętli to w zapytaniu nie widzę, ale czas 10 minut to calkiem sporo, tu już trzeba by się zagłębiać w strukturę danych i zobaczyć plan wykonania, wynik nie może być lepszy, to jest albo dobry, albo zły, patrząc na to co tam masz to nie wiem:

  1. Po co join po nieużywanej tabeli: CSTMP_B_MAGAZYN
  2. join z CSTMP_B_PRODUKT na moje wyczucie powinien być inner nie left

1 użytkowników online, w tym zalogowanych: 0, gości: 1