Pobranie innej wartości jeśli istnieje.

0

Cześć,
Muszę niestety klepnąć dość skomplikowaną (jak dla mnie) kwerendę przez co potrzebuję waszej pomocy. Tabela config:
-config_key
-config_value
-config_user
-config_initial
-config_category

Teraz chciałbym pobrać wszystkie rekordy z danej kategorii (np config_category = 1) które są wartościami "głównymi" (config_initial = 1). Jednakże jeśli istnieje taki sam klucz (config_key) który ma konkretnego usera (np config_user = 1) aby pobrało config_value tego właśnie usera.

W wielu zapytaniach w psełdokodzie wyglądało by to tak:

records = SELECT * FROM config WHERE config_initial = 1 AND config_category = 1;
for record in records:
    value = SELECT config_value FROM config WHERE config_key = record.config_key AND config_user = user;
    if(value):
        record.config_value = value
    endif
endfor

Mam nadzieję że dość jasno napisałem o co mi chodzi.
Z góry dziękuję za pomoc :)

1

pisane z głowy pod Firebirda, myślę że Postgress nie różni się aż tak bardzo , ale próbował bym z zagnieżdzonym selectem i case'em

select  
	case 
	   when (not ((SELECT first 1 b.config_value FROM config b WHERE b.config_key = a.config_key AND b.config_user = a.config_user) is null))
	   then (SELECT first 1 b.config_value FROM config b WHERE b.config_key = a.config_key AND b.config_user = a.config_user)
	else
	   a.config_value	 as config_value 
from 
	config a
where 
	a.config_initial = 1 AND a.config_category = 1
0

Gdyby ktoś potrzebował podobnego rozwiązania na postgresa (i na 99% na mysql'a) zamieszczam je poniżej:

SELECT a.config_key, a.config_value_type, 
	CASE
		WHEN (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND b.config_user = 1) IS NULL
		THEN (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND config_initial = 1)
		ELSE (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND b.config_user = 1) 
	END
FROM
	config AS a
WHERE
	a.config_initial = 1 AND a.config_category = 1
1

a co będzie jeśli

 (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND config_initial = 1)

albo

  (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND b.config_user = 1) 

zwrócą więcej niż jedną wartość ???

0

Nie zwróci (chociaż dziękuję @grzegorz_so za uwagę, wyjdę z psem i dopiszę aby pobierało tylko pierwszą wartość, tak na wszelki wypadek) ponieważ klasa w aplikacji dba o to aby była tylko jedna wartość dla danego klucza per user.

0

Aplikacja to aplikacja, może mieć błędy. A nie lepiej zapewnić unikalność wartości na poziomie bazy przez jakiś "constraints" typu "unique" albo unikalny indeks ?
Jeśli taką regułę "zaszyjesz" w bazie to będzie mniej podatna na potencjalne błędy w aplikacji. Zresztą po to mechanizm takich reguł został "wymyślony" aby sama baza mogła pilnować unikalności danych

0

Szczerze mówiąc bazodanowiec ze mnie żaden więc prosiłbym o więcej informacji. Indeks muszę dodać (myślałem że nie będzie kompletnie przydatny, ale jednak będzie). Wszystkie kolumny w której nie będzie mógł być null mają not null. Jedyne co mogę dodać to foreign key na kolumnę która wskazuję na kategorie danego klucza konfiguracyjnego. Ale ta w sumie jedna rzecz to wszystko co mogę zrobić. Dodatkowo odgórnym zarządzeniem jest aby aplikacja mogła działać na wszystkich możliwych bazach sql'owych co wymusza na mnie nie stosowanie funkcji.

0

"ponieważ klasa w aplikacji dba o to aby była tylko jedna wartość dla danego klucza per user."

kontrolę unikalności danych powinna kontrolować sama baza , np tak, tworząc "constraint"

ALTER TABLE TABLEXXX  ADD UNIQUE (FIELD1,FIELD2,FIELD3)

albo unikalny indeks

CREATE UNIQUE INDEX TABLE_INDEX  ON TABLEXXX(FIELD1,FIELD2,FIELD3)
0

W sumie masz rację. Nie pomyślałem wcześniej aby stworzyć wartość klucz_user i trzymać ją w bazie która automatycznie pilnowała by unikalności danych.

0

Trochę odszedłem od szczegółów budowy Twojej bazy bo nie w tym rzecz . Budując aplikację bazodanową , pakuj do bazy maksymalnie wiele ograniczeń i reguł (unikaty czy klucze obce ). Im więcej reguł pilnuje baza tym lepiej , bo jest bardziej odporna na błędy w aplikacji i błędy "userów" aplikacji . Tym samym zapewnisz sobie spójność i wymaganą unikalność danych w bazie. W przypadku naruszenia owych reguł user dostanie albo komunikat o błędzie albo aplikacja mu się wykrzaczy ( to zależy od aplikacji) ale dane w bazie będą spójne i unikalne tam gdzie mają takie być

0

Jeżeli dobrze zrozumiałem, to w tabeli config masz konfiguracje domyślną, plus konfiguracje użytkownika, pytanie tylko jak rozpoznajesz domyslną konfiguracje, wtedy mozna to zrobić joinem:

Pobrnie konfiguracji dla usera: 1

SELECT
    d.config_key
    ,COALESCE(u.config_value,d.config_value) as config_value
    ,1 config_user
    ,d.config_initial
    ,d.config_category
FROM
    config as d
    LEFT JOIN config as u on d.config_key=u.config_key
                                      and u.config_user = 1
WHERE
     d.config_initial = 1 
     AND d.config_category = 1    
0

@Panczo rozpoznawanie jest po kolumnie config_initial, ale i tak, jak pisałem wcześniej problem już rozwiązany :)

2

@NickOver wiem, ze problem jest rozwiązany, ale chciałem pokazać, że można to zrobić bez podzapytań, nawet Twoje zapytanie ma o jedno za dużo ;)
Swój poprzedni post poprawiłem tak, że spełni założenia
Bardziej w celach edukacyjnych, aby pokazań jak operować na danych, bez niepotrzebnych zagnieżdżeń w selectach.
Drobny tunning Twojego:

SELECT a.config_key, a.config_value_type, 
    CASE
        WHEN (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND b.config_user = 1) IS NULL
        THEN config_value
        ELSE (SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND b.config_user = 1) 
    END
FROM
    config AS a
WHERE
    a.config_initial = 1 AND a.config_category = 1

Po sugestiach @Marcin.Miga:

SELECT a.config_key, a.config_value_type, 
    COALESCE((SELECT b.config_value FROM config AS b WHERE b.config_key = a.config_key AND b.config_user = 1),config_value) as config_value
FROM
    config AS a
WHERE
    a.config_initial = 1 AND a.config_category = 1

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