Frage

Ich suche die unten stehende Abfrage etwas besser lesbar und modifizierbar Refactoring. Die erste Hälfte ist identisch mit dem zweiten, mit Ausnahme der Datenbank abgefragt aus (Tabellennamen gleich sind though.)

  SELECT
    Column 1 AS c1,
    ...
    Column N AS cN
  FROM
    database1.dbo.Table1

UNION

  SELECT
    'Some String' as c1,
    ...
    NULL as cN
  FROM
    database1.dbo.Table2

UNION

  SELECT
    Column 1 AS c1,
    ...
    Column N AS cN
  FROM
    database2.dbo.Table1

UNION

  SELECT
    'Some String' as c1,
    ...
    NULL as cN
  FROM
    database2.dbo.Table2

Diese Abfrage ist die Definition von DRY und ruft mich werden wieder -written, aber ich habe keine Ahnung, wie es geht!

Bearbeiten : Wir nicht Linq verwenden können, und wir wünschen unterschiedliche Ergebnisse; Ich suche die Abfrage kleiner in physischer Dateigröße, nicht in Treffer zu machen.

Bearbeiten : Die Datenbank, die ich Abfragen aus bin ist eine proprietäre ERP-Datenbank. Restrukturierung ist keine Option.

War es hilfreich?

Lösung

Das ist ein ziemlich Standard-SQL-Muster. Manchmal ist es einfach OOP / Procedural Code Prinzipien wie DRY zu SQL inadvisedly zu übertragen, aber sie sind nicht unbedingt übertragbar Konzepte.

Beachten Sie, wie leicht Sie die gesamte logische Gestaltung der Abfrage grok, gegen die Jagd durch Submodule. Wenn einer der Teilausdrücke eine zusätzliche Spalte hat, oder Spalten umgekehrt, würde es durchhalten. Dies ist im Grunde eine ziemlich einfache SQL-Anweisung als eine Ausführungseinheit grok, wo Aufschließschritt es wäre es durcheinander.

Und wenn Sie das Debuggen, ist es praktisch, den Text des Editor hervorgehoben Option verwenden zu können, Teile der Anweisung selektiv auszuüben - eine Technik, die nicht in prozeduralen Code vorhanden ist. OTOH, kann es chaotisch zu versuchen, die Stücke alle aufzuspüren, wenn sie in Ansichten verstreut sind etc. Auch CTEs kann diese unbequem machen.

Andere Tipps

Ich werde auf einem Glied hier gehen und sagen: auf der Grundlage der Informationen, die Sie uns gegeben haben;

Das ist so gut wie es geht zu erhalten

Eine Leistungsspitze, die ich von der Fledermaus zu sehen ist, mit UNION ALL statt UNION es sei denn, Sie absichtlich verschiedene Datensätze wollen. Eine einfache UNION Duplikate eliminieren, die Zeit in Anspruch nimmt. UNION ALL macht das nicht.

Sie könnte es umschreiben mit dynamischem SQL und einer Schleife, aber ich denke, das Ergebnis schlechter wäre. Wenn es genug doppelte Code ist der dynamischen SQL-Ansatz zu rechtfertigen, dann denke ich, es gerechtfertigt sein könnte.

Alternativ haben Sie darüber nachgedacht, die Logik aus der gespeicherten Prozedur in so etwas wie LINQ zu verschieben? Für viele ist dies keine Option, so ich frage nur.

Eine letzte Bemerkung: der Drang widerstehen zu beheben, was nur kaputt ist nicht es sauberer aussehen zu lassen. Wenn die Bereinigung aide in Wartung, Überprüfung usw., dann gehen sie.

Was ist das Problem? Zu lang? Zu repetitiv?

Manchmal hat man hässlich SQL - nicht viel können Sie dagegen tun können.

Ich sehe keine Möglichkeit, es zu bereinigen, wenn Sie separate Ansichten verwenden möchten, und dann Vereinigung sie zusammen.

Ich stimme für Ansichten, die in der Nähe genug, um ohne Overhead verhängen (Kosten OK, vielleicht eine kleine Compile-Zeit, aber das sollte alles sein). Dann wird Ihr Procs wird etwas von der Form

SELECT * FROM database1.view1
UNION
SELECT * FROM database1.view2
UNION
SELECT * FROM database2.view1
UNION
SELECT * FROM database2.view2

Ich bin mir nicht sicher, ob ich es noch weiter verdichten wollen würde, obwohl ich die meisten Plattformen erwarten würden toleriert es.

Auf dem dynamischen SQL-Thema - hier ist ein Beispiel - nicht sicher, ob es nicht besser ist. Der Vorteil ist, man muss nur einmal die SELECT-Liste schreiben.

DECLARE @Select1 varchar(1000)
DECLARE @Select2 varchar(1000)

DECLARE @SQL varchar(4000)


SET @Select1 = 'SELECT
    Column 1 AS c1,
    ...
    Column N AS cN'


SET @Select2 = 'SELECT
    ''Some String'' as c1,
    ...
    NULL as cN'


SET @SQL = @Select1 + ' FROM database1.dbo.Table1 '

SET @SQL = @SQL + ' UNION ' + @Select2 + ' FROM database1.dbo.Table2 '

SET @SQL = @SQL + ' UNION ' + @Select1 + ' FROM database2.dbo.Table1 '

SET @SQL = @SQL + ' UNION ' + @Select2 + ' FROM database2.dbo.Table2 '


EXEC @SQL

Wenn alle Ihre Procs so aussehen - Sie haben wahrscheinlich ein architektonisches Problem

.

Sind alle Ihre Anrufe nur table2 ein Nutzfeld haben? (Und wegen der UNION, nur am Ende einer Zeile mit?)

ich total zweite die Idee mit parametrisierte dynamischer SQL und / oder Code-Generierung für diesen Job geht, sogar so weit geht die Spaltenliste dynamisch mit INFORMATION_SCHEMA zu erzeugen. Dies ist nicht genau das, was Sie brauchen, aber es ist ein Anfang (man könnte eine Tabelle von Datenbanken und Tabellen erzeugt aus):

DECLARE @template AS varchar(MAX)
SET @template = 'SELECT {@column_list} FROM {@database_name}.dbo.{@table_name}'
DECLARE @column_list AS varchar(MAX)

SELECT @column_list = COALESCE(@column_list + ',', '') + COLUMN_NAME
FROM database1.dbo.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table_name
ORDER BY ORDINAL_POSITION

DECLARE @sql AS varchar(MAX)
SET @sql = @template
SET @sql = REPLACE(@sql, '{@column_list}', @column_list)
SET @sql = REPLACE(@sql, '{@database_name}', @database_name)
SET @sql = REPLACE(@sql, '{@table_name}', @table_name)

Abhängig von der Anzahl der zurückgegebenen Zeilen, können Sie am besten UNION mit ALL auf der wählt mit einer ausgewählten verschiedene Abfrage um ihn herum. Ich habe vor ein ähnliches Problem gesehen und hatten unterschiedliche Ausführungspläne für die beiden unterschiedlichen Arten

SELECT DISTINCT subquery.c1, subquery.cN
FROM
(
SELECT Column 1 AS c1, Column N AS cN FROM database1.dbo.Table1
UNION ALL
SELECT 'Some String' as c1, NULL as cN FROM database1.dbo.Table2
UNION ALL
SELECT Column 1 AS c1, Column N AS cN FROM database2.dbo.Table1
UNION ALL
SELECT 'Some String' as c1, NULL as cN FROM database2.dbo.Table2
) subquery
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top