Wpis z mikrobloga

Mirki z #bazydanych i #mysql , mam problem z zapytaniem:

Otóż mam następujące złożone zapytanie (jest ono zapisywane w widoku CREATE VIEW):


SELECT

'items'.'id' AS item_key_id, 'allegro_items'.'allegroId' AS 'allegro_items_allegroId', 'allegro_items'.'status' AS 'allegro_items_status', 'allegro_items'.'productId' AS 'allegro_items_productId', 'allegro_items'.'firstExport' AS 'allegro_items_firstExport', 'allegro_items'.'firstExportUserId' AS 'allegro_items_firstExportUserId', 'allegro_items'.'lastExport' AS 'allegro_items_lastExport', 'allegro_items'.'lastExportPhotos' AS 'allegro_items_lastExportPhotos', 'allegro_items'.'lastExportUserId' AS 'allegro_items_lastExportUserId', 'allegro_items'.'itemId' AS 'allegro_items_itemId', 'allegro_items'.'clientId' AS 'allegro_items_clientId', 'items'.'id' AS 'items_id', 'items'.'created' AS 'items_created', 'items'.'createdUserId' AS 'items_createdUserId', 'items'.'lastChanged' AS 'items_lastChanged', 'items'.'lastChangedPhotos' AS 'items_lastChangedPhotos', 'items'.'lastChangedUserId' AS 'items_lastChangedUserId', 'items'.'code' AS 'items_code', 'items'.'codeSortStart' AS 'items_codeSortStart', 'items'.'codeSortNum' AS 'items_codeSortNum', 'items'.'codeSortEnd' AS 'items_codeSortEnd', 'items'.'gtin' AS 'items_gtin', 'items'.'name' AS 'items_name', 'items'.'price' AS 'items_price', 'items'.'vat' AS 'items_vat', 'items'.'countWare' AS 'items_countWare', 'items'.'countOffer' AS 'items_countOffer', 'items'.'description' AS 'items_description', 'items'.'externalCode' AS 'items_externalCode', 'items'.'externalUrl' AS 'items_externalUrl', 'items'.'externalPrice' AS 'items_externalPrice', 'items'.'externalCustomMargin' AS 'items_externalCustomMargin', 'items'.'itemStatusId' AS 'items_itemStatusId', 'items'.'deliveryPriceListId' AS 'items_deliveryPriceListId', 'items'.'deliveryTimeId' AS 'items_deliveryTimeId', 'items'.'itemGroupId' AS 'items_itemGroupId', 'items'.'categoryId' AS 'items_categoryId', 'items'.'placeId' AS 'items_placeId', 'item_statuses'.'id' AS 'item_statuses_id', 'item_statuses'.'name' AS 'item_statuses_name', 'item_statuses'.'color' AS 'item_statuses_color', 'delivery_price_list'.'id' AS 'delivery_price_list_id', 'delivery_price_list'.'name' AS 'delivery_price_list_name', 'delivery_times'.'id' AS 'delivery_times_id', 'delivery_times'.'name' AS 'delivery_times_name', 'item_groups'.'id' AS 'item_groups_id', 'item_groups'.'name' AS 'item_groups_name',

(SELECT COUNT(*) FROM 'item_photos' WHERE 'item_photos'.'itemId' = 'items'.'id') AS count_photos,
(SELECT COUNT(*) FROM 'items_parameters' WHERE 'items_parameters'.'itemId' = 'items'.'id' AND 'items_parameters'.'valueNum' = 0) AS count_params,
(SELECT COUNT(*) FROM 'items_additional_descs' WHERE 'items_additional_descs'.'itemId' = 'items'.'id') AS count_additdescs

FROM 'items'
JOIN 'item_statuses' ON 'item_statuses'.'id' = 'items'.'itemStatusId'
LEFT JOIN 'delivery_price_list' ON 'delivery_price_list'.'id' = 'items'.'deliveryPriceListId'
LEFT JOIN 'delivery_times' ON 'delivery_times'.'id' = 'items'.'deliveryTimeId'
LEFT JOIN 'item_groups' ON 'item_groups'.'id' = 'items'.'itemGroupId'
LEFT JOIN 'allegro_items' ON 'allegro_items'.'itemId' = 'items'.'id'

Następnie pobieram co potrzebuje z tego widoku.

Ogólnie koncepcja jest następująca: w tabeli "items" mam towary, w tabeli "allegroitems" powiązanie ich z kontem allegro.
Pole 'allegroitems'.'clientId' oznacza ID konta allegro.

Otóż jeżeli towar jest niewystawiony - sprawa jest prosta - przez LEFT JOIN z allegro
items otrzymuje same nulle.
Jednak jeżeli zrobię tutaj WHERE clientId = 1000 i towar będzie wystawiony na innym koncie allegro, to po prostu nie zostanie on pobrany z bazy.

Gdyby był wystawiony tylko na jednym koncie allegro, to programowo w Javie mogę po prostu nie zwracać tych danych. Jednak w przypadku gdy towar wystawiony byłby na wielu kontach allegro, pojawia się problem taki, że jest on pobierany wiele razy. Tutaj też w teorii mógłbym to rozwiązać programowo w Javie - jednak dla paginacji z użyciem LIMIT jest to średnio możliwe.... albo raczej - bardzo trudne zadanie.

Jak zrobić mirki następującą rzecz:
1) Jeżeli towar jest nigdzie nie wystawiony, to w allegro_items mam same nulle
2) Jeżeli towar jest wystawiony na koncie o clientID 1000, to w przypadku:
a) pobierania tego towaru dla konta o clientID 1000 pokażą się dane w allegro_items
b) w przypaku pobierania danych dla konta o clientID 1005 pokażą się same nulle w allegro_items (lub ewentualnie dane konta 1000 - mogę programowo ich nie zwracać - to akurat żaden kłopot)
3) Jeżeli towar jest wystawiony na kontach 1000 i 1002 to na tych kontach dane pokażą się odpowiednio dla 1000 i 1002, a dla konta 1005 pokaża się nulle (lub jak wyżej - dane dla innego konta które usunę programowo)
4) Będzie bez problemu działać to z paginacją na LIMIT. Czyli że jak pobieram listę 200 towarów dla konta o ID 1000 to wtedy pobiera się 200 towarów (nie duplikują się itemsid).

Da się to jakoś prosto zrobić? Normalnie dałbym GROUP BY itemsid ale... no właśnie - jak zmusić group by, żeby w pierwszej kolejności pokazało dane allegro_items dla konta o clientID 1000? Bo dla reszty może pokazać albo nulle albo dane z innego konta (mogę je programowo usunąć, jeżeli to będzie prostsze).

#programowanie #bazydanych #mysql #sql #webdev
  • 4
@lukasj: jeżeli chcesz mieć ładny pager (limit) to z tymi joinami tego nie uzyskasz, bo jeżeli produkt będzie na więcej niż jedno powiązanie które dołączasz joinami (np. jest na więcej niż jednym koncie allegro) to zawsze Ci będzie duplikować produkty. Musisz to inaczej zaprojektować i rozbić na osobne zapytania.
@rico91: akurat tutaj produkt ma zawsze jedno powiązanie z joinami które dołączam. Dlatego też np pobierana jest tylko ilość zdjęć i ilość parametrów (żeby nie było ich więcej). Chodzi bardziej o to, zeby ten jeden jedyny join (allegroitems) dołączać w inny sposób. Np z group by ... having albo coś takiego. Tylko, żeby w razie czego jak na koncie o ID 1000 jest wystawiony towar, to żeby na koncie o
@rico91: ewentualnie: mogę dać tutaj: where allegroitem.clientId = 1005 OR allegroitem.clientId is NULL.

Zadziała poprawnie dla towarów niewystawionych na żadnym koncie, lub wystawionych tylko na koncie o ID 1005. Ale jeżeli towar jest wystawiony na koncie o ID 1000 to co wtedy? Nie znajdzie go jako pusty (niewystawiony). Jak zrobić, żeby tam pojawiły się nulle? Ewentualnie dodać jeszcze jeden JOIN kiedy allegro_items nie jest null? Tylko jak coś takiego
@rico91: Już wiem ( ͡° ͜ʖ ͡°)

wystarczy dać LEFT JOIN allegroitems ON ... AND clientID = 1005, wtedy łączy tylko to albo daje null

niestety minus taki, że będę musiał zrezygnować z widoku i po prostu wykonywać zapytanie wszędzie, ale powiedzmy że lepsze to niż duplikowanie rekordów albo przerabianie paginacji... Chyba że jest jakiś inny sposób, żeby jednak ten widok zostawić?