eine Zeilenanzahl nach SELECT-Anweisung müssen: Was ist der optimale SQL-Ansatz?

StackOverflow https://stackoverflow.com/questions/243782

  •  04-07-2019
  •  | 
  •  

Frage

Ich versuche, eine Spalte aus einer einzigen Tabelle zu wählen (keine Verknüpfungen) und ich brauche die Zählung der Anzahl der Zeilen, idealerweise, bevor ich die Zeilen beginnen abruft. Ich habe zwei Ansätze kommen, die die Informationen liefern die ich brauche.

Ansatz 1:

SELECT COUNT( my_table.my_col ) AS row_count
  FROM my_table
 WHERE my_table.foo = 'bar'

Dann

SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'

oder Ansatz 2

SELECT my_table.my_col, ( SELECT COUNT ( my_table.my_col )
                            FROM my_table
                           WHERE my_table.foo = 'bar' ) AS row_count
  FROM my_table
 WHERE my_table.foo = 'bar'

Ich tue dies, weil meine SQL-Treiber (SQL Native Client 9.0) mich nicht erlaubt, SQLRowCount auf einer SELECT-Anweisung zu verwenden, aber ich brauche die Anzahl der Zeilen in meinem Ergebnis kennen, um ein Array zu verteilen, bevor Informationen Zuweisen es. Die Verwendung eines dynamisch zugewiesenen Behälter ist leider keine Option in diesem Bereich meines Programms.

Ich bin besorgt darüber, dass das folgende Szenario auftreten:

  • SELECT für Zählung auftritt
  • Eine weitere Anweisung auftritt, Hinzufügen oder Entfernen einer Zeile
  • Entfernen
  • SELECT für Daten auftreten, und plötzlich das Array ist die falsche Größe.
      -In schlimmsten Fall, wird diese versuchen, Daten über die Arrays Grenzen zu schreiben und mein Programm zum Absturz bringen.

Hat Ansatz 2 verbietet dieses Problem?

Auch Will einer der beiden Ansätze schneller sein? Wenn ja, welche?

Schließlich ist es ein besserer Ansatz, dass ich in Betracht ziehen sollte (vielleicht ein Weg, um den Fahrer geben die Anzahl der Zeilen in einem SELECT-Ergebnis mit SQLRowCount? Anweisen,)

Für diejenigen, die gefragt, ich native C ++ bin mit mit den oben genannten SQL-Treiber (von Microsoft).

War es hilfreich?

Lösung

Es gibt nur zwei Möglichkeiten, zu 100% sicher zu sein, dass die COUNT(*) und die tatsächliche Abfrage konsistente Ergebnisse geben:

  • die COUNT(*) mit der Abfrage In Kombination, wie in Ihrem Ansatz 2. ich das Formular, das Sie zeigen in Ihrem Beispiel empfehlen, nicht die korrelierte Unterabfrage in dem Kommentar von kogus gezeigt.
  • Mit
  • zwei Abfragen, wie in Ihrem Ansatz 1, nachdem eine Transaktion in SNAPSHOT oder SERIALIZABLE Isolationsstufe beginnen.

Mit einem dieser Isolationsstufen wichtig, weil jede andere Isolationsstufe neue Zeilen von anderen Clients erstellt ermöglicht in der aktuellen Transaktion sichtbar zu werden. Lesen Sie die MSDN-Dokumentation auf SET TRANSACTION ISOLATION für weitere Details.

Andere Tipps

Wenn Sie SQL Server verwenden, nach Ihrer Anfrage können Sie die @@ RowCount Funktion (oder wenn Ihre Ergebnismenge könnten mehr als 2 Milliarden Zeilen verwenden Sie die RowCount_Big () -Funktion). Dadurch wird die Anzahl der Zeilen, die von der vorherige Anweisung oder der Anzahl der Zeilen zurück durch eine insert / update / delete-Anweisung betroffen ausgewählt.

SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'

SELECT @@Rowcount

Oder wenn Sie rudern wollen zählen im Ergebnis enthalten ähnlich geschickt 2 # Approach, können Sie die die OVER-Klausel .

SELECT my_table.my_col,
    count(*) OVER(PARTITION BY my_table.foo) AS 'Count'
  FROM my_table
 WHERE my_table.foo = 'bar'

die OVER-Klausel verwendet, wird eine deutlich bessere Leistung hat als eine Unterabfrage mit der Zeilenanzahl zu erhalten. die @@ RowCount Mit die beste Leistung haben, weil die es keine Abfragekosten für die Auswahl sein wird @@ RowCount Anweisung

Update in Reaktion auf einen Kommentar: Das Beispiel gab ich die Anzahl der Zeilen in der Partition geben würde - in diesem Fall definiert durch „PARTITION BY my_table.foo“. Der Wert der Spalte in jeder Zeile ist die Anzahl der Zeilen mit dem gleichen Wert von my_table.foo. Da Ihr Beispiel Abfrage hatte die Klausel „WHERE my_table.foo =‚bar‘“, wird alle Zeilen in der Ergebnismenge den gleichen Wert von my_table.foo haben wird und daher der Wert in der Spalte wird das gleiche für alle Zeilen und gleich sein (in dieser Fall) dies die Anzahl der Zeilen in der Abfrage.

Hier ist ein besseres / einfacheres Beispiel dafür, wie eine Spalte in jeder Zeile enthalten, die die Gesamtanzahl der Zeilen in der Ergebnismenge ist. Entfernen Sie einfach die optionale Partition By-Klausel.

SELECT my_table.my_col, count(*) OVER() AS 'Count'
  FROM my_table
 WHERE my_table.foo = 'bar'

Ansatz 2 wird immer eine Zählung zurück, die Ergebnismenge entspricht.

Ich schlage vor, Sie die Unterabfrage zu Ihrer äußeren Abfrage verknüpfen jedoch zu gewährleisten, dass die Bedingung auf Ihrer Zählung auf dem Datensatz, den Zustand entspricht.

SELECT 
  mt.my_row,
 (SELECT COUNT(mt2.my_row) FROM my_table mt2 WHERE mt2.foo = mt.foo) as cnt
FROM my_table mt
WHERE mt.foo = 'bar';

Wenn Sie die Anzahl der Zeilen darüber besorgt, dass die Bedingung erfüllen, in den wenigen Millisekunden seit Ausführung der Abfrage und den Abruf der Ergebnisse ändern können, Sie könnte / sollte die Abfragen innerhalb einer Transaktion ausführen:

BEGIN TRAN bogus

SELECT COUNT( my_table.my_col ) AS row_count
FROM my_table
WHERE my_table.foo = 'bar'

SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
ROLLBACK TRAN bogus

Dies würde die richtigen Werte zurückgeben, immer.

Außerdem, wenn Sie SQL Server verwenden, können Sie @@ ROWCOUNT verwenden, um die Anzahl der Zeilen letzte Anweisung betroffen zu bekommen, und leiten Sie die Ausgabe von real Abfrage in einer temporären Tabelle oder eine Tabelle Variable, so kann man alles zusammen zurückkehren, und keine Notwendigkeit einer Transaktion:

DECLARE @dummy INT

SELECT my_table.my_col
INTO #temp_table
FROM my_table
WHERE my_table.foo = 'bar'

SET @dummy=@@ROWCOUNT
SELECT @dummy, * FROM #temp_table

Hier sind einige Ideen:

  • Gehen Sie mit Ansatz # 1 und die Array-Größe ändern, weitere Ergebnisse zu halten oder eine Art zu verwenden, die automatisch als notwendig die Größe (Sie erwähnen nicht, welche Sprache Sie verwenden, so kann ich nicht mehr spezifisch sein).
  • Sie könnten beide Aussagen in Ansatz # 1 innerhalb einer Transaktion führen die zählt, sind die gleichen Zeiten zu gewährleisten, wenn die Datenbank dies unterstützt.
  • Ich bin mir nicht sicher, was Sie mit den Daten zu tun, aber wenn es möglich ist, die Ergebnisse zu verarbeiten, ohne zuerst alle von ihnen speichern könnte dies die beste Methode sein.

Wenn Sie wirklich besorgt, dass Ihre Zeilenanzahl zwischen dem select count und der select-Anweisung ändern, warum wählen Sie nicht Ihre Zeilen in eine temporäre Tabelle zuerst? Auf diese Weise wissen Sie, Sie synchron sein wird.

Warum Sie nicht Ihre Ergebnisse in einen Vektor setzen? Auf diese Weise müssen Sie die Größe, bevor die Hand nicht kennen.

Sie könnten ein besseres Muster denken, wollen mit den Daten dieser Art zu tun.

Keine Selbst prespecting SQL-Treiber werden Ihnen sagen, wie viele Zeilen Ihre Abfrage vor der Rückkehr in den Zeilen zurück, weil die Antwort ändern könnte (wenn Sie eine Transaktion verwenden, die ihre eigenen Probleme. Erstellt)

Die Anzahl der Zeilen wird sich nicht ändern -. Für ACID und SQL google

IF (@@ROWCOUNT > 0)
BEGIN
SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'
END

Nur diese hinzugefügt werden, da dies das Top-Ergebnis in Google für diese Frage ist. In SQLite verwenden ich dies die rowcount zu erhalten.

WITH temptable AS
  (SELECT one,two
   FROM
     (SELECT one, two
      FROM table3
      WHERE dimension=0
      UNION ALL SELECT one, two
      FROM table2
      WHERE dimension=0
      UNION ALL SELECT one, two
      FROM table1
      WHERE dimension=0)
   ORDER BY date DESC)
SELECT *
FROM temptable
LEFT JOIN
  (SELECT count(*)/7 AS cnt,
                        0 AS bonus
   FROM temptable) counter
WHERE 0 = counter.bonus
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top