Łączenie zapytania SQL pętlą if lub for

Łączenie zapytania SQL pętlą if lub for
Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

Hej,

Tworzę teraz wtyczkę w Pythonie, gdzie w jednej z funkcji występuje konieczność złożenia zapytania SQL składanych z 6 różnych parametrów (4 z listy Combo, 2 z Editext), które musi uwzględnać każdą możliwą kombinację, począwszy od ich braku: a + h (a to "Select * FROM [Nazwa_Tabeli]" , a h to "Order by ID DESC" ), po a + b + c + d + e + f + g + h (b-g zawsze zaczyna się od "WHERE [parametr] ")z możliwością braku jednego/dwóch/trzech... z nich.

Jak to zrobić, aby nie mnożyć w kodzie "elifów" tyle że będzie ich 2x tyle, co całego kodu wtyczki :-D

Z góry dziękuje za każdą pomoc

DR
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1135
0

Ja osobiście używam Query builder, ale niekiedy nie da się uniknąć if'ow

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0
Dregorio napisał(a):

Ja osobiście używam Query builder, ale niekiedy nie da się uniknąć if'ow

To odpada, bo to pisane jest w Spyderze, jako Python, a części zapytania sql, traktowane są początkowo jako tekst (ewentualnie konwertowane z inta)

woolfik
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1611
0

Zrób jedno zapytanie z parametrami. Odpowiadając na komentarz:

Kopiuj
where 1 = 1
    and (col1 = :Param1 or :Param1=:Param1)
    and (col2 = :Param2 or :Param2=:Param2)
    ...

jednak zaznaczam, że to tylko pomysł i trzeba to sprawdzić na konkretnej bazie w konkretnych przypadkach bo może się okazać, że optymalizator będzie stawał okoniem.

PA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3891
0

Jakby do a dopisać where 1=1
a b - g zaczynały się zamiast na where tylko and, to połaczenie a + b + c + d + e + f + g + h da ci poprawne zapytanie sql

PA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3891
1

Where 1=1 jest po to, abyś mógł doklejać warunki bez sprawdzenia czy już jest jakis poprzedni.

Załóżmy że

a=select * from tabela where 1=1
B=
C=
D= and cold=3
E=
F= and colf=4
G=
H=order by kolumna

Bez żadnego if łączysz zmienne i masz poprawny SQL, w każdej sytuacji, jak nie ma warunków też.

AN
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 989
0

Cieżko stwierdzić o co Ci chodzi bo nie zamieściłeś żadnego przykładu i niejasno przekazujesz swoje intencje ale z tego co zrozumiałem to:

Kopiuj
clauses = [clause for clause in ("1 = 1", a, b, c, d, e, f, g) if clause]
clauses = " AND ".join(clauses)
query = f`SELECT * FROM table WHERE {clasues} ORDER BY ID DESC`

Tylko to nie do końca będzie odporne na SQL INJECTION

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

Jeśli chodzi o przykład to wygląda to tak (fragmenty):

Kopiuj
sql
 if b == '' and c == '' and d == '' and str(e) == '' and f == 'dowolny' and g == 'dowolny':
            Zap = a + h
            print (1)
            self.wysw()
 elif b is not '' and c is '' and d is '' and str(e) == '' and f == 'dowolny' and g == 'dowolny': 
            b = '\'' + b + '\''
            sqlb = ' and TERYT = ' + b #kod 
            Zap = a + sqlb + h
            print (2)
            self.wysw()
 elif b is '' and c is not '' and d is '' and str(e) == '' and f == 'dowolny' and g == 'dowolny': 
            c = '\'%' + c + '%\'' #nazwa 
            sqlb = ' and TERYT IN (select TERYT from POWIATY where upper (NAZWA) like upper(' + c + '))'
            Zap = a + sqlb + h
            print (3)
            self.wysw() 
            """kilkadziesiąt kombinacji dalej"""
 elif b is not '' and c is '' and d is not '' and str(e) != '' and f != 'dowolny' and g == 'dowolny' : 
            b = '\'' + b + '\''
            sqlb= ' and TERYT = ' + b #kod 
            c = '\'%' + c + '%\'' #nazwa powiatu
            sqlc = ' and TERYT IN (select TERYT from POWIATY where upper (NAZWA) like upper(' + c + '))'
            sqld = ' and ROK_PLANOWANIA = ' + d #Rok planowania
            e = '\'' + e+ '\''
            sqle= ' and NR_UMOWY = ' + sqle #Numer umowy
            f = '\'' + f + '\''
            sqlf = ' and WYKONAWCA = ' + f #wykonawca
            Zap = a + sqlb + sqlc + sqld + sqle + sqlf + h
            print (59)
            self.wysw()
        else:
            b= '\'' + b + '\''
            sqlb = ' and TERYT = ' + b #kod 
            c = '\'%' +c + '%\'' #nazwa 
            sqlc = ' and TERYT IN (select TERYT from POWIATY where upper (NAZWA) like upper(' + c + '))'
            sqld= ' and ROK_PLANOWANIA = ' + d #Rok planowania
            e = '\'' + e + '\''
            sqle= ' and NR_UMOWY = ' + e #Numer umowy
            f = '\'' + f + '\''
            sqlf = ' and WYKONAWCA_KOD = ' + f #wykonawca
            g = '\'' + g + '\''
            sqlg = ' and STATUS_ZAM_KOD = ' + g #status 
            Zap = sqla + sqlb + sqlc + sqld + sqle + sqlf + sqlg + h
            print (60)
            self.wysw()

Każdą kombinację numeruje w celu sprawdzenia czy jest wychwytywana (i jest to sprawdzenie ile ich jest)

_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
0

To jest PHP ale dokładnie ten sam problem:

Kopiuj
$Where='';
$Having='';
if($HaveAzonId==2) $Having.="(HaveAzonId)\t"; else if($HaveAzonId==1) $Having.="(not HaveAzonId)\t";
if($HaveAgrements==2) $Having.="(not HaveAgrements)\t"; else if($HaveAgrements==1) $Having.="(HaveAgrements)\t";
if($HaveAuthorsId==2) $Having.="(not HaveAuthorsId)\t"; else if($HaveAuthorsId==1) $Having.="(HaveAuthorsId)\t";
if($HaveDomain==2) $Having.="(not HaveDomain)\t"; else if($HaveDomain==1) $Having.="(HaveDomain)\t";
if($HaveAbstract==2) $Having.="(not HaveAbstract)\t"; else if($HaveAbstract==1) $Having.="(HaveAbstract)\t";
if($$HaveKeywords==2) $Having.="(not HaveKeywords)\t"; else if($HaveKeywords==1) $Having.="(HaveKeywords)\t";

if(strlen($Having)>0) $Having=' having '.str_replace("\t","and",trim($Having));
if($EditFilterLength>0) $Where.="and(R.Number like '%{$EditFilter}%')";

$sql
=
	"select R.Id,R.Number,R.Page1 PageCount,".
	"ifnull(R.AzonId,0)>0 HaveAzonId,".
	"ifnull((select sum(A.`Agreement`<>1) from rpt_authors A where A.`ReportId`=R.`Id`),-1)=0 HaveAgrements,".
	"ifnull((select sum((ifnull(L.AffilationId,0)>0)and(ifnull(U.`AzonId`,0)>0)) from rpt_authors A, rpt_aliases L, rpt_users U where A.`ReportId`=R.`Id` and L.`Id`=A.`AliasId` and U.`Id`=L.`UserId`),-1)>0 HaveAuthorsId,".
	"ifnull((select count(K.`Id`)>0 from `rpt_report_keypack` P, `rpt_keymono` K where P.`ReportId`=R.`Id` and K.`KeyPackId`=P.`KeyPackId`),0) HaveKeywords,".
	"ifnull(R.DomainId,0)>0 HaveDomain,".
	"ifnull(length(R.Abstract),-1)>0 HaveAbstract ".
	"from rpt_reports R ".
	"where (R.Project=1)$Where$Having ".
	"order by R.Number"
;

Działa dobrze.

pms_enable_synaptics
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 152
0

Łączenie zapytania SQL pętlą if lub for

A co to pętla if?

PA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3891
1

Nie znam sie na pythonie, ale nie potrzebujesz sprawdzać warunkow czy wystepują, psedo kod:

Kopiuj
wh = ' where 1=1 '
if b is not '':
    b = '\'' + b + '\''
    wh = wh + ' and TERYT = ' + b #kod 
if c is not '': 
    c = '\'%' + c + '%\'' #nazwa powiatu
    wh = wh + ' and TERYT IN (select TERYT from POWIATY where upper (NAZWA) like upper(' + c + '))'              
if d is not '': 
    wh = wh + ' and ROK_PLANOWANIA = ' + d #Rok planowania
if  str(e) != '';
    e = '\'' + e+ '\''
    wh = wh + ' and NR_UMOWY = ' + sqle #Numer umowy
if f != 'dowolny':
    f = '\'' + f + '\''
    wh = wh + ' and WYKONAWCA = ' + f #wykonawca
if g != 'dowolny':
    g = '\'' + g + '\''
    wh = wh + ' and STATUS_ZAM_KOD = ' + g #status   

Zap = sqla + wh + h
       

Bez względu na kombinacje warunków dostaniesz prawidłowy sql. Pozostaje kwestia SQL Injection, ale nie siedzę w pythonie by coś zaproponować

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

OK dziękuje, a ten Injection może jakoś wpłynąć?

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

Kod @Pancho wygląda obiecująco, tyle że te zapytania wykonują się na raz, a ma być 1 rezultat w oknie poniżej.
Przez co kontrola otrzymanych wyników jest mniejsza.
Zaraz wrzucę ogólny wygląd

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

screenshot-20220719150051.png

PA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3891
0

Ja nie rozumiem, ja sklejam 1 zapytanie, więc skąd liczba mnoga?

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

Jak uruchamiam i zaczynam od wyboru województwa (w tym przykładzie: kujawsko-pomorskie) to (na princie) wyświetla mi się to:
screenshot-20220719150657.png

PA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3891
0

pokaż kod, boz mojego fragmentu jest sklajeny tylko where.

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

Oto on:

Kopiuj
sqlPodst = 'SELECT * FROM ZARZADZANIE.ZAMOWIENIA where 1=1'
        order= ' ORDER BY ID DESC'
        kod = self.dlg.comboBox_10.currentText()
        powiat = self.dlg.comboBox_9.currentText()
        NrUm = self.dlg.textEdit_4.toPlainText()
        Rok = self.dlg.textEdit.toPlainText()
        wyk = self.dlg.comboBox_7.currentText()
        stat = self.dlg.comboBox_8.currentText()
        global Zap
        if kod is not '':
            kod = '\'' + kod + '\''
            tresc = ' and TERYT = ' + kod #kod TERYT
            Zap = sqlPodst + tresc + order
            print (Zap)
            self.wysw()
        if powiat is not '':  
            powiat = '\'%' + powiat + '%\'' #nazwa powiatu
            tresc = ' and TERYT IN (select TERYT from ZARZADZANIE.POWIATY where upper (POWIAT_NAZWA) like upper(' + powiat + '))'
            Zap = sqlPodst + tresc + order
            print (Zap)
            self.wysw()
        if Rok is '':
            tresc = ' and ROK_PLANOWANIA = ' + Rok #Rok planowania
            Zap = sqlPodst + tresc + order
            print (Zap)
            self.wysw()
        if str(NrUm) != '':
            NrUm = '\'' + NrUm + '\''
            tresc= ' and NR_UMOWY = ' + NrUm #Numer umowy
            Zap = sqlPodst + tresc + order
            print (Zap)
            self.wysw()
        if wyk != 'dowolny':
            wyk = '\'' + wyk + '\''
            tresc = ' and WYKONAWCA_KOD = ' + wyk #wykonawca
            Zap = sqlPodst + tresc + order
            print (Zap)
            self.wysw()
        if stat != 'dowolny':
            stat = '\'' + stat + '\''
            tresc = ' and STATUS_ZAM_KOD = ' + stat #status 
            Zap = sqlPodst + tresc + order
            print (Zap)
            self.wysw()
        else:
            Zap = sqlPodst + order
            print (Zap)
            self.wysw()    

PA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3891
0

zwróć uwagę na to co robisz w kodzie.

  1. Ja w swoim buduje warunek where i przechowuje go w zmiennej wh, Ty natomiast budujesz warunek w zmiennej tresc, ale nie dodajesz do niej warunków tylko nadpisujesz.
  2. Nie wiem co robi self.wysw() (podejrzewam że wyświetla wyniki na podstawie zap), to kolejny błąd logiczny, sklej najpierw całe zapytanie, póżniej dopiero wyświet;
  3. masz błedy warunek w if dla roku
  4. Ten else na końcu nie jest do niczego potrzebny
Kopiuj
sqlPodst = 'SELECT * FROM ZARZADZANIE.ZAMOWIENIA where 1=1'
        order= ' ORDER BY ID DESC'
        kod = self.dlg.comboBox_10.currentText()
        powiat = self.dlg.comboBox_9.currentText()
        NrUm = self.dlg.textEdit_4.toPlainText()
        Rok = self.dlg.textEdit.toPlainText()
        wyk = self.dlg.comboBox_7.currentText()
        stat = self.dlg.comboBox_8.currentText()
        global Zap
        tresc=''
        if kod is not '':
            kod = '\'' + kod + '\''
            tresc = tresc + ' and TERYT = ' + kod #kod TERYT
        if powiat is not '':  
            powiat = '\'%' + powiat + '%\'' #nazwa powiatu
            tresc = tresc + ' and TERYT IN (select TERYT from ZARZADZANIE.POWIATY where upper (POWIAT_NAZWA) like upper(' + powiat + '))'
        if Rok is not '':
            tresc = tresc + ' and ROK_PLANOWANIA = ' + Rok #Rok planowania
        if str(NrUm) != '':
            NrUm = '\'' + NrUm + '\''
            tresc= tresc + ' and NR_UMOWY = ' + NrUm #Numer umowy
        if wyk != 'dowolny':
            wyk = '\'' + wyk + '\''
            tresc = tresc + ' and WYKONAWCA_KOD = ' + wyk #wykonawca
        if stat != 'dowolny':
            stat = '\'' + stat + '\''
            tresc = tresc + ' and STATUS_ZAM_KOD = ' + stat #status 

Zap = sqlPodst + tresc + order
print (Zap)
self.wysw()

Karol Śpila
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 73
0

Działa, 'where 1=1' było już wcześniej wpisane w zapytaniu, więc stwierdziłem, że nie ma sensu tego rozdzielać. Dużo krótszy i szybciej ładują się dane, więc pozostaje tylko poczekać na reakcję szefa (który na urlopie jest, a ja dopiero w II połowie sierpnia)

I trochę się sam łapie, że nie wpadło mi do głowy nadpisywanie zapytania :-P

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.