Optymalizacja zapytania SQL

Optymalizacja zapytania SQL
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

Witam,
Zwracam się z ogromną prośbą o sprawdzenie poniższego kodu SQL i udzielenie pomocy w jego optymalizacji - czy jest w ogóle taka możliwość?
Czy da się to napisać bardziej optymalnie - zarówno w kontekście wydajności jak również długości tekstu. Jest to tylko fragment zapytania, który stworzyłem a mam ograniczoną liczbę znaków w programie w którym je umieszczę i mam małe obawy, że mogę się nie wyrobić :-/.

Niestety SQL nie jest moją mocną stroną.

Kopiuj
SELECT SUM(DeK_Kwota) FROM CDN_Testowa.CDN.DekretyKonta	WHERE DeK_Strona = 1 AND DeK_DataDok <= 
		(SELECT EDN_DataOpe FROM [CDN_Testowa].[CDN].[EwidDodNag] WHERE EDN_NumerPelny = 'EDK/1/2015') 
	AND DeK_AccId = (
		SELECT Acc_AccId FROM CDN_Testowa.CDN.Konta WHERE Acc_Numer = (
			SELECT Kat_KontoSegmentWN FROM CDN_Testowa.CDN.Kategorie WHERE Kat_KatID = (
				SELECT EDN_KatID FROM [CDN_Testowa].[CDN].[EwidDodNag] WHERE EDN_NumerPelny = 'EDK/1/2015'))
			AND Acc_OObId = (
				SELECT OOb_OObID FROM CDN_Testowa.CDN.OkresyObrach	WHERE OOb_DataOtw <= (
					SELECT EDN_DataOpe FROM [CDN_Testowa].[CDN].[EwidDodNag] WHERE EDN_NumerPelny = 'EDK/1/2015') 
					AND OOb_DataKoncowa >= (
						SELECT EDN_DataOpe FROM [CDN_Testowa].[CDN].[EwidDodNag] WHERE EDN_NumerPelny = 'EDK/1/2015')))

Głównie chodzi o to czy da się jakoś ograniczyć te zapytania - np. gdy w ostatniej linijce porównuję czas czy nie jest >= lub <= to tworzę dwa podzapytania z tej samej tabeli no i zastanawiam się czy nie dałoby się tego zrobić jednym zapytaniem?

Mam nadzieję, że wszystko jest czytelne (wcięcia odnoszą się do kolejnego podzapytania).
Aha, i ten numer 'EDK/1/2015' to tylko przykładowy string w celu sprawdzenia czy zapytanie działa - później zostanie zmieniony na zmienną.
No i oczywiście pomijam kwestię wyrzucenia nawiasów kwadratowych, które w tym przypadku są zbędne.

Z góry bardzo dziękuję za wszelką pomoc.

edytowany 2x, ostatnio: Księgowy
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
1

jak się gdzieś nie walnąłem to powinno być to

Kopiuj
SELECT
  SUM(d.DeK_Kwota)  
FROM
  [CDN_Testowa].[CDN].[DekretyKonta] d,
  [CDN_Testowa].[CDN].[EwidDodNag] n,
  [CDN_Testowa].[CDN].[Konta] k,
  [CDN_Testowa].[CDN].[Kategorie] a,
  [CDN_Testowa].[CDN].[OkresyObrach] o  
WHERE
  d.DeK_Strona = 1   
  AND n.EDN_NumerPelny = 'EDK/1/2015'
  AND d.DeK_DataDok <= n.EDN_DataOpe
  AND n.EDN_KatID = a.Kat_KatID
  AND o.OOb_DataOtw <= n.EDN_DataOpe
  AND o.OOb_DataKoncowa >= n.EDN_DataOpe
  AND k.Acc_OObId = o.OOb_OObID
  AND a.Acc_Numer = k.Acc_Numer

Wydajnościowo nie wiem, które będzie lepsze - trzeba by sprawdzić, chociaż podzapytania zazwyczaj są wolniejsze.

A co do wcięć (bo Twoje naprawdę nie poprawiają czytelności) to można to zapisać np. tak http://poorsql.com/

Kopiuj
SELECT SUM(DeK_Kwota)
FROM CDN_Testowa.CDN.DekretyKonta
WHERE DeK_Strona = 1
	AND DeK_DataDok <= (
		SELECT EDN_DataOpe
		FROM [CDN_Testowa].[CDN].[EwidDodNag]
		WHERE EDN_NumerPelny = 'EDK/1/2015'
		)
	AND DeK_AccId = (
		SELECT Acc_AccId
		FROM CDN_Testowa.CDN.Konta
		WHERE Acc_Numer = (
				SELECT Kat_KontoSegmentWN
				FROM CDN_Testowa.CDN.Kategorie
				WHERE Kat_KatID = (
						SELECT EDN_KatID
						FROM [CDN_Testowa].[CDN].[EwidDodNag]
						WHERE EDN_NumerPelny = 'EDK/1/2015'
						)
				)
			AND Acc_OObId = (
				SELECT OOb_OObID
				FROM CDN_Testowa.CDN.OkresyObrach
				WHERE OOb_DataOtw <= (
						SELECT EDN_DataOpe
						FROM [CDN_Testowa].[CDN].[EwidDodNag]
						WHERE EDN_NumerPelny = 'EDK/1/2015'
						)
					AND OOb_DataKoncowa >= (
						SELECT EDN_DataOpe
						FROM [CDN_Testowa].[CDN].[EwidDodNag]
						WHERE EDN_NumerPelny = 'EDK/1/2015'
						)
				)
		)

lub tak http://www.freeformatter.com/sql-formatter.html

Kopiuj
SELECT
  SUM(DeK_Kwota)  
FROM
  CDN_Testowa.CDN.DekretyKonta  
WHERE
  DeK_Strona = 1   
  AND DeK_DataDok <= (
    SELECT
      EDN_DataOpe    
    FROM
      [CDN_Testowa].[CDN].[EwidDodNag]    
    WHERE
      EDN_NumerPelny = 'EDK/1/2015'    
  )   
  AND DeK_AccId = (
    SELECT
      Acc_AccId    
    FROM
      CDN_Testowa.CDN.Konta    
    WHERE
      Acc_Numer = (
        SELECT
          Kat_KontoSegmentWN      
        FROM
          CDN_Testowa.CDN.Kategorie      
        WHERE
          Kat_KatID = (
            SELECT
              EDN_KatID        
            FROM
              [CDN_Testowa].[CDN].[EwidDodNag]        
            WHERE
              EDN_NumerPelny = 'EDK/1/2015'        
          )      
        )     
        AND Acc_OObId = (
          SELECT
            OOb_OObID      
          FROM
            CDN_Testowa.CDN.OkresyObrach      
          WHERE
            OOb_DataOtw <= (
              SELECT
                EDN_DataOpe        
              FROM
                [CDN_Testowa].[CDN].[EwidDodNag]        
              WHERE
                EDN_NumerPelny = 'EDK/1/2015'        
            )       
            AND OOb_DataKoncowa >= (
              SELECT
                EDN_DataOpe        
              FROM
                [CDN_Testowa].[CDN].[EwidDodNag]        
              WHERE
                EDN_NumerPelny = 'EDK/1/2015'        
            )      
          )    
        )

Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
edytowany 2x, ostatnio: abrakadaber
1
  1. Naucz się SQL.
  2. Coś albo jest optymalne, albo nie jest optymalne. To nie jest skala. Powiedzieć "bardziej optymalne" to jakby powiedzieć "bardziej najlepsze".
  3. Jeśli program łączy się bezpośrednio z CDN_Testowa, to można usunąć
Kopiuj
CDN_Testowa.
  1. Bez schematu i opisu problemu wywróżyłem tak:
Kopiuj
DECLARE @EDN_NumerPelny varchar(10)
SET @EDN_NumerPelny = 'EDK/1/2015'

SELECT SUM(DeK.DeK_Kwota)
FROM CDN_Testowa.CDN.EwidDodNag		 EDN
INNER JOIN CDN_Testowa.CDN.OkresyObrach OOb ON OOb.OOb_DataOtw <= EDN.EDN_DataOpe AND OOb.OOb_DataKoncowa >= EDN.EDN_DataOpe
INNER JOIN CDN_Testowa.CDN.Kategorie	Kat ON Kat.Kat_KatID = EDN.EDN_KatID
INNER JOIN CDN_Testowa.CDN.Konta		Acc ON Acc.Acc_OObId = OOb.OOb_OObID AND Acc.Acc_Numer = Kat.Kat_KontoSegmentWN
INNER JOIN CDN_Testowa.CDN.DekretyKonta DeK ON DeK.DeK_Strona = 1 AND DeK.DeK_DataDok <= EDN.EDN_DataOpe AND DeK.DeK_AccId = Acc.Acc_AccId 
WHERE EDN.EDN_NumerPelny = @EDN_NumerPelny
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

@abrakadaber Dziękuję Ci ślicznie za pomoc!!!
Rzeczywiście Twój kod wygląda "troszkę" czytelniej ;-)
Jak wrócę do domu to od razu go wypróbuję czy działa ;D.
Kombinowałem w podobny sposób (z aliasami), ale gdzieś robiłem błąd, który powodował, że nie działało i błędnie doszedłem do wniosku, że to zła droga :/.

Przy okazji zapytam: kiedy należy stosować aliasy a kiedy podzapytania w klauzuli WHERE ew. kiedy klauzulę JOIN?!
Wszystkie metody chyba dają ten sam wynik tylko, że Twoje rozwiązanie z aliasami jest zdecydowanie czytelniejsze i krótsze!!!

j_s_r_n napisał(a):
  1. Naucz się SQL.
  1. Uczę się.
  2. Jestem księgowym (jak sama nazwa nicku sugeruje) a nie programistą, więc proszę o wyrozumiałość.
  3. Umiem dość dobrze (jak na księgowego) programować w C++, ale SQL do tej pory nie był mi w zasadzie do niczego potrzebny...
j_s_r_n napisał(a):

Coś albo jest optymalne, albo nie jest optymalne. To nie jest skala. Powiedzieć "bardziej optymalne" to jakby powiedzieć "bardziej najlepsze".

Nie zgodzę się. To jest tak jakby coś było dobre/złe a chcieć zrobić coś lepiej. Jeśli moje rozwiązanie jest złe, słabe lub dobre, ale nie najlepsze to bardziej optymalnie oznacza po prostu jeszcze lepsze - chociaż nie koniecznie najlepsze (optymalne).

j_s_r_n napisał(a):

Jeśli program łączy się bezpośrednio z CDN_Testowa, to można usunąć

Tak, masz rację. Jednak dlatego, że najpierw testuję te zapytania w SQL Managment-cie to muszę podawać nazwę bazy danych do której się odnoszę. Docelowo zamierzałem usunąć nazwę bazy danych i nawiasy kwadratowe.

j_s_r_n napisał(a):

Bez schematu i opisu problemu wywróżyłem tak: (...)

No tak, ale w zasadzie czym różni się Twoje rozwiązanie od mojego? Pod jakim względem jest ono lepsze od mojego? Czy JOIN-y są wydajniejsze czy chodzi o coś innego? Jak ocenisz rozwiązanie, które przedstawił @abrakadaber?
Powtórzę również pytanie: kiedy należy stosować aliasy, WHERE a kiedy JOIN? Dla mnie osobiście najlepiej wyglądają aliasy -> porównując swój kod i Twój z tym co przedstawił @abrakadaber nie ma nawet porównania!

Jeszcze raz dziękuję i pozdrawiam.

fourfour
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:627
1

Aliasy ułatwiają czytanie i pisanie, więc należy stosować je tam, gdzie .... ułatwiają czytanie i pisanie :)
Join używa się do łączenia tabel, a where do warunków. Tak w uproszczeniu, generalizując :)

abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
1

dokładnie - aliasy po prostu skracają zapis. Podzapytania należy używać tylko wtedy kiedy to konieczne, nie powinno się ich używać tak jak Ty to zrobiłeś, np. tu

Kopiuj
Acc_OObId = (
          SELECT
            OOb_OObID      
          FROM
            CDN_Testowa.CDN.OkresyObrach      
          WHERE
            OOb_DataOtw <= (
              SELECT
                EDN_DataOpe        
              FROM
                [CDN_Testowa].[CDN].[EwidDodNag]        
              WHERE
                EDN_NumerPelny = 'EDK/1/2015'        
            )       
            AND OOb_DataKoncowa >= (
              SELECT
                EDN_DataOpe        
              FROM
                [CDN_Testowa].[CDN].[EwidDodNag]        
              WHERE
                EDN_NumerPelny = 'EDK/1/2015'        
            )      
          )

czyli kiedy wynik podzapytania jest przyrównywany do jakiejś wartości - teraz działa ale może się zdarzyć że dla jakiegoś EDN_NumerPelny zostanie zwrócone kilka rekordów OOb_OObID i wtedy wszystko się wysypie. W większości przypadków podzapytania wydłużają czas całego zapytania, tzn. zapisanie tego samego z podzapytaniami i bez będzie się wykonywało szybciej bez podzapytań (chociaż znam przypadki, gdzie było odwrotnie).

Następnie zapis

Kopiuj
select a.*, b.* from tabA a, tabB b where a.id = b.id

jest równoważny zapisowi

Kopiuj
select a.*, b.* from tabA a inner join tabB b on a.id = b.id

i dla bazy z "poważnym" optymalizatorem nie ma różnicy bo plan wykonania będzie taki sam. Natomiast już LEFT/RIGHT/OUTER JOIN to jest inna sprawa i nie da się ich inaczej zapisać. Ja preferuję zapis z WHERE zamiast INNER JOIN bo jest dla mnie czytelniejszy. Generalnie trzeba trochę wyczucia z joinami bo może się okazać, że coś co powinno działać nie działa (chodzi o to, które warunki można umieścić po ON a które trzeba po WHERE)


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
edytowany 1x, ostatnio: abrakadaber
1

Przeprasza za to

  1. Naucz się SQL.

Nie lubię emoticon i jak na to teraz patrzę to wygląda jak rozkaz, albo nagana. Chodziło mi bardziej o to, że skoro i tak będziesz go używał to łatwiej ci będzie pracować, jak go będziesz znał.

Zgodnie ze słownikiem

optymalny - najlepszy z możliwych w jakichś warunkach

Kopiuj
USE CDN_Testowa

sprawi, że kolejne zapytania będą wykonywane w kontekście bazy CDN_Testowa, czyli w SSMS można tak:

Kopiuj
USE CDN_Testowa
DECLARE @EDN_NumerPelny VARCHAR(10)
SET @EDN_NumerPelny = 'EDK/1/2015'
 
SELECT SUM(DeK.DeK_Kwota)
FROM CDN.EwidDodNag         EDN
INNER JOIN CDN.OkresyObrach OOb ON OOb.OOb_DataOtw <= EDN.EDN_DataOpe AND OOb.OOb_DataKoncowa >= EDN.EDN_DataOpe
INNER JOIN CDN.Kategorie    Kat ON Kat.Kat_KatID = EDN.EDN_KatID
INNER JOIN CDN.Konta        Acc ON Acc.Acc_OObId = OOb.OOb_OObID AND Acc.Acc_Numer = Kat.Kat_KontoSegmentWN
INNER JOIN CDN.DekretyKonta DeK ON DeK.DeK_Strona = 1 AND DeK.DeK_DataDok <= EDN.EDN_DataOpe AND DeK.DeK_AccId = Acc.Acc_AccId 
WHERE EDN.EDN_NumerPelny = @EDN_NumerPelny
Księgowy napisał(a):

No tak, ale w zasadzie czym różni się Twoje rozwiązanie od mojego? Pod jakim względem jest ono lepsze od mojego? Czy JOIN-y są wydajniejsze czy chodzi o coś innego? Jak ocenisz rozwiązanie, które przedstawił @abrakadaber?

Subselect w waruknu po jednej stronie równości to potencjalny crash.

@abra

0

cd. (nie założę konta)

Zapytanie @abrakadaber używa "ukrytych" joinów, co dla mnie zmniejsza czytelność kodu. Jego kod wizualnie wydaje się lżejszy(a to tylko kwestia formatowania), ale trzeba się doszukiwać intencji i kolejności łączenia tabel. Poza tym ma beznadziejne aliasy.

[Kategorie] a

abrakadaber
abrakadaber
k już było zajęte - kto ci broni zamienić na swoje aliasy?
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

Okey, wszystko działa jak należy! W kodzie był mały błąd, ale udało się go szybko wyeliminować ;-)
Jeszcze raz wszystkim ogromnie dziękuję za udział w dyskusji i okazaną pomoc!!!
pozdrawiam

KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

Ehh, myślałem, że już sobie poradzę, ale jednak znowu pojawiły się problemy ;-(

Chciałem więc ponownie prosić o pomoc.

Czy jest możliwość, bez korzystania ze zmiennych lub funkcji, by zapytanie zwróciło różnicę lub sumę dwóch innych zapytań? Chodzi o to, że mam dwa zapytania typu:

Kopiuj
	SELECT 
		SUM(dekret.DeK_Kwota)  
	FROM
		[CDN_Testowa].[CDN].[DekretyKonta] dekret,
		[CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
		[CDN_Testowa].[CDN].[Konta] konta,
		[CDN_Testowa].[CDN].[Kategorie] kategoria,
		[CDN_Testowa].[CDN].[OkresyObrach] okres  
	WHERE	
			dekret.DeK_Strona = 1   
		AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
		AND dekret.DeK_AccId = konta.Acc_AccId
		AND ewidencja.EDN_NumerPelny = 'EDK/1/2015'
		AND ewidencja.EDN_KatID = kategoria.Kat_KatID
		AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
		AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
		AND konta.Acc_OObId = okres.OOb_OObID
		AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer

oraz

Kopiuj
	SELECT 
		BO.BOE_KwotaWn 
	FROM 
		[CDN_Testowa].[CDN].[BOElem] BO,
		[CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
		[CDN_Testowa].[CDN].[Konta] konta,
		[CDN_Testowa].[CDN].[Kategorie] kategoria,
		[CDN_Testowa].[CDN].[OkresyObrach] okres
	WHERE 
			ewidencja.EDN_NumerPelny = 'EDK/1/2015'
		AND ewidencja.EDN_KatID = kategoria.Kat_KatID
		AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
		AND konta.Acc_AccId = BO.BOE_AccId
		AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
		AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
		AND konta.Acc_OObId = okres.OOb_OObID

A chciałbym, żeby zapytanie zwróciło sumę tych dwóch zapytań (docelowo będą 4 zapytania).
Czy mogę prosić jeszcze chociaż o naprowadzenie?

Z góry dziękuję!

1

Poniżej różnica twoich zapytań

Kopiuj
SELECT SUM(SKLADNIK_SUMY)
FROM
(SELECT 
    SUM(dekret.DeK_Kwota)  AS SKLADNIK_SUMY
FROM
    [CDN_Testowa].[CDN].[DekretyKonta] dekret,
    [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
    [CDN_Testowa].[CDN].[Konta] konta,
    [CDN_Testowa].[CDN].[Kategorie] kategoria,
    [CDN_Testowa].[CDN].[OkresyObrach] okres  
WHERE    
        dekret.DeK_Strona = 1   
    AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
    AND dekret.DeK_AccId = konta.Acc_AccId
    AND ewidencja.EDN_NumerPelny = 'EDK/1/2015'
    AND ewidencja.EDN_KatID = kategoria.Kat_KatID
    AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
    AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
    AND konta.Acc_OObId = okres.OOb_OObID
    AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
UNION ALL
SELECT 
    BO.BOE_KwotaWn * -1
FROM 
    [CDN_Testowa].[CDN].[BOElem] BO,
    [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
    [CDN_Testowa].[CDN].[Konta] konta,
    [CDN_Testowa].[CDN].[Kategorie] kategoria,
    [CDN_Testowa].[CDN].[OkresyObrach] okres
WHERE 
        ewidencja.EDN_NumerPelny = 'EDK/1/2015'
    AND ewidencja.EDN_KatID = kategoria.Kat_KatID
    AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
    AND konta.Acc_AccId = BO.BOE_AccId
    AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
    AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
    AND konta.Acc_OObId = okres.OOb_OObID) SKLADNIKI_SUMY
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
1

ale po co tak kombinowac

Kopiuj
select
  DeK_Kwota - KwotaWn
from
  (SELECT 
        SUM(dekret.DeK_Kwota)  DeK_Kwota
    FROM
        [CDN_Testowa].[CDN].[DekretyKonta] dekret,
        [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
        [CDN_Testowa].[CDN].[Konta] konta,
        [CDN_Testowa].[CDN].[Kategorie] kategoria,
        [CDN_Testowa].[CDN].[OkresyObrach] okres  
    WHERE    
            dekret.DeK_Strona = 1   
        AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
        AND dekret.DeK_AccId = konta.Acc_AccId
        AND ewidencja.EDN_NumerPelny = 'EDK/1/2015'
        AND ewidencja.EDN_KatID = kategoria.Kat_KatID
        AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
        AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
        AND konta.Acc_OObId = okres.OOb_OObID
        AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer),
  (SELECT 
        BO.BOE_KwotaWn 
    FROM 
        [CDN_Testowa].[CDN].[BOElem] BO,
        [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
        [CDN_Testowa].[CDN].[Konta] konta,
        [CDN_Testowa].[CDN].[Kategorie] kategoria,
        [CDN_Testowa].[CDN].[OkresyObrach] okres
    WHERE 
            ewidencja.EDN_NumerPelny = 'EDK/1/2015'
        AND ewidencja.EDN_KatID = kategoria.Kat_KatID
        AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
        AND konta.Acc_AccId = BO.BOE_AccId
        AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
        AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
        AND konta.Acc_OObId = okres.OOb_OObID)

i już - po prostu bierzesz jedno zapytanie jako tabelę A (musi być wtedy w nawiasie całe zapytanie) oraz drugie zapytanie jako tabelę B i po prostu odejmujesz ich pola. Chociaż w tym konkretnym przypadku zapewne dało by się to poskracać (zapisać jednym selectem) ale jeśli czas wykonania jest akceptowalny (i tak dużo większe znaczenie będą miały odpowiednie indeksy) to po co się męczyć :p


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

@abrakadaber Jesteś genialny! Dzięluję jeszcze raz! ;-)
Takie rozwiązanie z pewnością mi wystarczy, ale jak byś miał jeszcze troszkę cierpliwości do mojej osoby i chwilkę wolnego czasu to czy mógłbyś podać jakiś króciutki przykład (nie musi bazować na moich SELECT-ach) o jakie skracanie Ci chodziło w jednym SELECTcie? Chciałbym na przyszłość zrozumieć ideę.
Też się zastanawiałem czy jest możliwość nie pisania we wszystkich zapytaniach tych samych danych, które wydobywam w zapytaniu a które się powtarzają (np. EDN_NumerPelny lub Kat_KatID, które zawsze będą wspólne dla pozostałych zapytań).

edytowany 1x, ostatnio: Księgowy
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

Teraz sobie uświadomiłem, że chyba jest taka możliwość mniej więcej w taki sposób: (pisane na szybko w pracy - zapewne z błędami, ale chodzi o ideę):

Kopiuj
SELECT
  DeK_Kwota - KwotaWn
FROM
  (SELECT 
        SUM(dekret.DeK_Kwota)  DeK_Kwota
    FROM
        [CDN_Testowa].[CDN].[DekretyKonta] dekret,
        [CDN_Testowa].[CDN].[Konta] konta,
        [CDN_Testowa].[CDN].[OkresyObrach] okres  
    WHERE    
            dekret.DeK_Strona = 1   
        AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
        AND dekret.DeK_AccId = konta.Acc_AccId
        
        AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
        AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
        AND konta.Acc_OObId = okres.OOb_OObID
        AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer),
  (SELECT 
        BO.BOE_KwotaWn 
    FROM 
        [CDN_Testowa].[CDN].[BOElem] BO,
        [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
        [CDN_Testowa].[CDN].[Konta] konta,
        [CDN_Testowa].[CDN].[OkresyObrach] okres
    WHERE 
        
        AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
        AND konta.Acc_AccId = BO.BOE_AccId
        AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
        AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
        AND konta.Acc_OObId = okres.OOb_OObID),
        [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
	[CDN_Testowa].[CDN].[Kategorie] kategoria,

WHERE
	ewidencja.EDN_NumerPelny = 'EDK/1/2015'
	AND ewidencja.EDN_KatID = kategoria.Kat_KatID

Czy dobrze kombinuję? ;-)

fourfour
Może i dobrze, ale nie wiem, co na to powie optymalizator... :)
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
1

bardziej chodziło mi o to, że BO.BOE_AccId równa się konta.Acc_AccId, które też jest znane w pierwszym zapytaniu. Teoretycznie to powinno dać ten sam wynik

Kopiuj
SELECT 
  SUM(dekret.DeK_Kwota) - Min(BO.BOE_KwotaWn)
FROM
  [CDN_Testowa].[CDN].[DekretyKonta] dekret,
  [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
  [CDN_Testowa].[CDN].[Konta] konta,
  [CDN_Testowa].[CDN].[Kategorie] kategoria,
  [CDN_Testowa].[CDN].[OkresyObrach] okres,
  [CDN_Testowa].[CDN].[BOElem] BO  
WHERE    
  dekret.DeK_Strona = 1   
  AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
  AND dekret.DeK_AccId = konta.Acc_AccId
  AND ewidencja.EDN_NumerPelny = 'EDK/1/2015'
  AND ewidencja.EDN_KatID = kategoria.Kat_KatID
  AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
  AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
  AND konta.Acc_OObId = okres.OOb_OObID
  AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
  AND konta.Acc_AccId = BO.BOE_AccId

ale to pod warunkiem, że [CDN_Testowa].[CDN].[BOElem] czyli drugie zapytanie zwróci TYLKO jeden rekord. No nie jestem do końca przekonany czy to coś przyśpieszy (wątpię) a na pewno zaciemni zapytanie


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

Super, dziękuję bardzo ;-)
Ostatnie, już krótkie pytanie: czy te MIN() jest dla bezpieczeństwa, gdyby BO.BOE_KwotaWn zwróciła więcej rekordów niż jeden, czy jest tam może jeszcze z innych względów?
Ogólnie to powinien być zwrócony tylko jeden rekord.
pozdrawiam!

abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:7 miesięcy
  • Postów:6610
1

w moim zapytaniu (teoretycznie) BO.BOE_KwotaWn będzie jedna (znaczy jeden rekord) ale dekret.DeK_Kwota może ich być kilka. Jeśli usuniesz SUM i MIN i wykonasz takie zapytanie

Kopiuj
SELECT 
  dekret.DeK_Kwota,
  BO.BOE_KwotaWn
FROM
  [CDN_Testowa].[CDN].[DekretyKonta] dekret,
  [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
  [CDN_Testowa].[CDN].[Konta] konta,
  [CDN_Testowa].[CDN].[Kategorie] kategoria,
  [CDN_Testowa].[CDN].[OkresyObrach] okres,
  [CDN_Testowa].[CDN].[BOElem] BO  
WHERE    
  dekret.DeK_Strona = 1   
  AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
  AND dekret.DeK_AccId = konta.Acc_AccId
  AND ewidencja.EDN_NumerPelny = 'EDK/1/2015'
  AND ewidencja.EDN_KatID = kategoria.Kat_KatID
  AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
  AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
  AND konta.Acc_OObId = okres.OOb_OObID
  AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
  AND konta.Acc_AccId = BO.BOE_AccId

to dostaniesz np. takie dane

dekret.DeK_Kwota BO.BOE_KwotaWn
12 5
43 5
17 5
84 5
dzieje się tak ponieważ nie masz połączonej tabeli BO i DEKRET i robi się iloczyn katezjański, czyli każdy z każdym. Jeśli dałbyś SUM(BO.BOE_KwotaWn) to by był zafałszowany wynik bo BO.BOE_KwotaWn zsumowało by tyle razy ile będzie rekordów dekret.DeK_Kwota. Można też zamiast MIN użyć grupowania - będzie to wyglądało tak
Kopiuj
SELECT 
  SUM(dekret.DeK_Kwota) - BO.BOE_KwotaWn
FROM
  [CDN_Testowa].[CDN].[DekretyKonta] dekret,
  [CDN_Testowa].[CDN].[EwidDodNag] ewidencja,
  [CDN_Testowa].[CDN].[Konta] konta,
  [CDN_Testowa].[CDN].[Kategorie] kategoria,
  [CDN_Testowa].[CDN].[OkresyObrach] okres,
  [CDN_Testowa].[CDN].[BOElem] BO  
WHERE    
  dekret.DeK_Strona = 1   
  AND dekret.DeK_DataDok <= ewidencja.EDN_DataOpe
  AND dekret.DeK_AccId = konta.Acc_AccId
  AND ewidencja.EDN_NumerPelny = 'EDK/1/2015'
  AND ewidencja.EDN_KatID = kategoria.Kat_KatID
  AND okres.OOb_DataOtw <= ewidencja.EDN_DataOpe
  AND okres.OOb_DataKoncowa >= ewidencja.EDN_DataOpe
  AND konta.Acc_OObId = okres.OOb_OObID
  AND kategoria.Kat_KontoSegmentWN = konta.Acc_Numer
  AND konta.Acc_AccId = BO.BOE_AccId
group by
  BO.BOE_KwotaWn

Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
edytowany 1x, ostatnio: abrakadaber
KS
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 8 lat
  • Postów:41
0

Jeszcze raz serdecznie Ci dziękuję za pomoc - szczególnie za te długie przykłady!!!
Z resztą chyba już sobie poradzę ;-)
pozdrawiam!

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)