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

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

0

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

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)

0

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

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.

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

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ż.

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:

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

0

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

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)

0

To jest PHP ale dokładnie ten sam problem:

$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.

0

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

A co to pętla if?

1

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

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ć

0

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

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

0

screenshot-20220719150051.png

0

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

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

0

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

0

Oto on:

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()    

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
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()

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

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