Meine eigentliche Arbeitsabfrage war ein innerer Join, aber dieses einfache Beispiel mit Cross-Join scheint das Problem fast immer zu reproduzieren.
SELECT *
FROM (
SELECT 1 UNION ALL
SELECT 2
) AA ( A )
CROSS JOIN (
SELECT NEWID() TEST_ID
) BB ( B )
Bei meinem inneren Join hatte ich viele Zeilen, für die ich mit der Funktion NEWID () jeweils eine GUID hinzufügte, und für etwa 9 von 10 solcher Zeilen ergab die Multiplikation mit der virtuellen 2-Zeilen-Tabelle die erwarteten Ergebnisse, nur 2 Kopien davon die gleiche GUID, während 1 von 10 unterschiedliche Ergebnisse liefern würde. Dies war gelinde gesagt unerwartet und machte es mir wirklich schwer, diesen Fehler in meinem Skript zur Generierung von Testdaten zu finden.
Wenn Sie sich die folgenden Abfragen mit nicht deterministischen Funktionen getdate und sysdatetime ansehen, werden Sie dies nicht sehen, ich jedenfalls nicht - ich sehe immer den gleichen datetime-Wert in beiden Endergebniszeilen.
SELECT *
FROM (
SELECT 1 UNION ALL
SELECT 2
) AA ( A )
CROSS JOIN (
SELECT GETDATE() TEST_ID
) BB ( B )
SELECT *
FROM (
SELECT 1 UNION ALL
SELECT 2
) AA ( A )
CROSS JOIN (
SELECT SYSDATETIME() TEST_ID
) BB ( B )
Ich verwende derzeit SQL Server 2008 und arbeite derzeit daran, meine Zeilen mit GUIDs in eine Tabellenvariable zu laden, bevor ich mein Skript zur Generierung zufälliger Daten fertigstelle. Sobald ich sie als Werte in einer Tabelle im Gegensatz zur virtuellen Tabelle habe, verschwindet das Problem.
Ich habe eine Problemumgehung, suche jedoch nach Möglichkeiten zur Problemumgehung ohne tatsächliche Tabellen oder Tabellenvariablen.
Während ich dies schrieb, versuchte ich erfolglos diese Möglichkeiten: 1) Platzieren der newid () in einer verschachtelten virtuellen Tabelle:
SELECT *
FROM (
SELECT 1 UNION ALL
SELECT 2
) AA ( A )
CROSS JOIN (
SELECT TEST_ID
FROM (
SELECT NEWID() TEST_ID
) TT
) BB ( B )
2) Umschließen der newid () in einen Besetzungsausdruck wie:
SELECT CAST(NEWID() AS VARCHAR(100)) TEST_ID
3) Umkehren der Reihenfolge des Auftretens der virtuellen Tabellen innerhalb des Join-Ausdrucks
SELECT *
FROM (
SELECT NEWID() TEST_ID
) BB ( B )
CROSS JOIN (
SELECT 1 UNION ALL
SELECT 2
) AA ( A )
4) mit unkorreliertem Kreuz anwenden
SELECT *
FROM (
SELECT NEWID() TEST_ID
) BB ( B )
CROSS APPLY (
SELECT 1 UNION ALL
SELECT 2
) AA ( A )
Kurz bevor ich diese Frage endgültig postete, habe ich dies anscheinend mit Erfolg versucht, es scheint ein korreliertes Kreuz zu gelten:
SELECT *
FROM (
SELECT NEWID() TEST_ID
) BB ( B )
CROSS APPLY (
SELECT A
FROM (
SELECT 1 UNION ALL
SELECT 2
) TT ( A )
WHERE BB.B IS NOT NULL
) AA ( A )
Hat jemand eine andere elegantere, einfachere Problemumgehung? Ich möchte wirklich keine Kreuzanwendung oder Korrelation für eine einfache Zeilenmultiplikation verwenden, wenn ich nicht muss.