PHP 7.xx: fbclient.dll bzw. gds32.dll wird nicht installiert.

Forum für Fragen rund um Firebird-Software von Drittanbietern.

Moderator: martin.koeditz

vr2
Beiträge: 213
Registriert: Fr 13. Apr 2018, 00:13

Hallo Bernd, bfuerchau,

das ursprüngliche select einzupacken will man doch gerade vermeiden, weil das 2 selects bedeutet, um an die Anzahl und die Nutzdaten ranzukommen. Die Verwendung der window function count(...) over (...) gibt einem die Möglichkeit, beides mit einer Abfrage zu bekommen. Da können natürlich auch where Bedingungen vorkommen, das war doch nur ein einfaches Beispiel. Firebird 3 hat window functions seit knapp 4 Jahren. Wie bfuerchau schon schrieb, window functions sind SQL Standard. row_count soweit ich weiß nicht - nagelt mich nicht fest, den aktuellen SQL-Standard gibt es nur zu kaufen. Bei relationalen Datenbanken wird Satzanzahl der Ergebnismenge über die Aggregatfunktion count umgesetzt, dh ist Teil einer Abfrage, nicht Teil der Übermittlung. Genauso wie es keine Satznummer gibt, bzw nur als window function row_number() over (...). Das bezieht sich aber nur auf die konkrete Ergebnismenge, also Teil der Abfrage.

Es ist fast immer eine gute Idee, standardkonform zu arbeiten. Dann kann man Produkte aussortieren, die das an wichtigen Stellen nicht sind und bei den anderen von Komformität ausgehen. Andernfalls kann es Größenordnungen an Mehrarbeit und Gefrickel bedeuten statt sauberem Design, bloß weil ein Hersteller den Standard nicht umsetzt. Das sollte genau deren Problem sein, nicht unseres.

Grüße, Volker
Hamburgo
Beiträge: 125
Registriert: Di 28. Mai 2019, 17:28

@bfuerchau:

upps, da habe ich mich wohl ein wenig missverständlich ausgedrückt.

Natürlich schneide ich den "where <Bedingung>"-Teil für den "Select count(*)" mit raus, sonst funktioniert das ja nicht.

Wie zuvor schon ausgeführt habe, brauche ich diesen Wert bei allen selects, denen eine Bildschirm-Ausgabe folgt und das sind schätzungsweise 90%.

Ha, das ist ja lustig !!! Mein Geburtstag liegt im April 1958 und Deiner ?

Auch ich fühle mich nicht zu alt, um noch stetig was neues zu lernen, darunter fällt nur nicht unbedingt Spezial-Wissen für eine gewisse DB.

Ich habe jetzt z.B. gelernt, wie ich meinen PHP-Server dazu befähige im Batch WhatsApp-Nachrichten mit einer Festnetz-Nr. zu versenden, ohne ein SmartPhone dran zu hängen. Das sind dann eher die Herausforderungen, wo ich noch gern Kraft reinstecke.
Hamburgo
Beiträge: 125
Registriert: Di 28. Mai 2019, 17:28

Hallo Volker,

ich schmeiße hier mal einen für meine Zwecke klassischen Select rein.

Bitte baue mir den mal so um, wie es Deinem Code-Vorschlag entspricht.

Vielleicht verstehe ich dann die Vorzüge Deines Lösungs-Vorschlags für mein Problem:

Code: Alles auswählen

		SELECT 
                         RID_POSITIONEN,
                         POSITIONS_NR,
                         SORTIERUNG,
                         ARTIKEL_NR,
                         RECHNUNGS_TEXT1,
                         RECHNUNGS_TEXT2,
                         AUFTRAG,
                         VK_PREIS,
                         VK_ANGEBOT,
                         VK_AUFTRAG,
                         VK_RECHNUNG,
                         VK_GUTSCHRIFT,
                         GESAMT,
                         EINHEIT_CODE,
                         STUNDEN,
                         MINUTEN,
                         STUNDEN_GESAMT,
                         MINUTEN_GESAMT,
                         RELATIONEN,
                         STATUS,
                         STAND
                 FROM
                         POSITIONEN
                 WHERE
                         QUELLEN_NR = '".$DbData[$Order['SubjektNr']]."' AND 
			 STATUS     < '".$Flag['Delete']."'
		 ORDER BY
                         SORTIERUNG ASC, 
                         POSITIONS_NR ASC 
Danke im Voraus !!!

Gruß
Bernd
bfuerchau
Beiträge: 484
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Das Problem ist, dass die Windowfunctions ein zusätzliches Argument benötigen:

select ....xxx, count(*) over (xxx) ...

Damit erhält man die Anzahl Vorkommen von XXX.
Dein Select lässt sich ganz einfach umbauen:

with xTmp as (
SELECT
RID_POSITIONEN,
POSITIONS_NR,
SORTIERUNG,
ARTIKEL_NR,
RECHNUNGS_TEXT1,
RECHNUNGS_TEXT2,
AUFTRAG,
VK_PREIS,
VK_ANGEBOT,
VK_AUFTRAG,
VK_RECHNUNG,
VK_GUTSCHRIFT,
GESAMT,
EINHEIT_CODE,
STUNDEN,
MINUTEN,
STUNDEN_GESAMT,
MINUTEN_GESAMT,
RELATIONEN,
STATUS,
STAND
FROM
POSITIONEN
WHERE
QUELLEN_NR = '".$DbData[$Order['SubjektNr']]."' AND
STATUS < '".$Flag['Delete']."'
)

select xTmp.*, (select count(*) from xTmp) xcount
from xTmp
ORDER BY
SORTIERUNG ASC,
POSITIONS_NR ASC
vr2
Beiträge: 213
Registriert: Fr 13. Apr 2018, 00:13

Hallo Bernd, bfuerchau,
Hamburgo hat geschrieben: Mo 1. Jul 2019, 19:51 Hallo Volker,

ich schmeiße hier mal einen für meine Zwecke klassischen Select rein.
Bitte baue mir den mal so um, wie es Deinem Code-Vorschlag entspricht.
Du packst ans Ende Deines select parts (wo im select Part ist eigentlich egal) ein count(*) over ().
Window functions können auch einen leeren over-Part haben: over (). Sie nutzen dann die Abfragemenge, ohne sie weiter zu partitionieren oder zu sortieren.

Code: Alles auswählen

select rid_positionen, positions_nr, ..., stand, count(*) over () anzahl
from positionen
where quellen_nr = '".$DbData[$Order['SubjektNr']]."' 
and status  < '".$Flag['Delete']."'
order by sortierung, positions_nr 
Die Lösung von bfuerchau mit der CTE und dem subselect darüber für die Gesamtanzahl ist Größenordnungen langsamer, subselect ist fast immer kritisch, was Performance angeht. Und CTE ebenfalls, wenn sie mehrfach abgefragt wird, und das wird sie hier durch das subselect. Schaut euch einfach mal den Abfrageplan der beiden Varianten an. Ich hatte eine kleine Testtabelle namens ram mit 30K Sätzen und einem unique Index idx_ram_ui auf Feldern der where-Bedingung, die CTE hieß bei mir tmp.

Bei der CTE/subselect-Variante ist der Plan

PLAN (TMP RAM INDEX (IDX_RAM_UI))
PLAN SORT (TMP RAM INDEX (IDX_RAM_UI))

bei der window function-Variante hingegen

PLAN SORT (RAM INDEX (IDX_RAM_UI))

Das CTE/subselect braucht 18 sek bei 22 Mio indexed reads, die Variante mit window function 600 msek bei 30K indexed reads! Bei einer größeren Tabelle kann man den CTE/subselect-Ansatz vergessen.

Das ist ja gerade einer Vorteile von window functions, sie erzeugen die Abfragemenge nicht nochmal neu. Stellt euch das eher vor wie einen eingehängten Seiteneffekt bei der sonstigen Abfrageverarbeitung (natürlich kann man window functions auch pur verwenden). Und bei der SQL-Generierung ist die Lösung auch einfacher, da Du den Ausdruck mit der window function einfach als weiteres Feld im select Part anhängst.

Grüße, Volker
Antworten