2009-01-28 139 views
1

我正在尋找重構下面的查詢更可讀和可修改的東西。上半年是相同的第二,從查詢的數據庫外(表名是相同的,但。)你會如何編寫這個查詢?

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 

此查詢的DRY的定義,並呼籲給我重新寫,但我不知道如何!

編輯:我們不能使用linq,我們希望得到不同的結果;我正在尋找使物理文件大小更小的查詢,而不是返回結果。

編輯:我查詢的數據庫是專有的ERP數據庫。重組它不是一種選擇。

+0

你基本上是試圖運行對其中一個或多個字段可能無法在某些存在不同名稱的表相同的查詢這些表格,但大部分其他領域在所有表格中都是共同的,然後將它們組合在一起? – BenAlabaster 2009-01-29 19:16:37

+0

@balabaster - 是的,那正是我正在做的。 – 2009-01-29 19:49:52

回答

2

這是一個非常標準的SQL模式。有時,很容易將OOP /程序代碼原理(如DRY)轉換爲SQL,但它們不一定是可轉換的概念。

請注意,您可以輕鬆地完成查詢的整個邏輯設計,而不是通過子模塊搜索。如果其中一個子表達式有一個額外的列,或者列顛倒了,它將伸出。這基本上是一個非常簡單的SQL語句,作爲一個執行單元,分解它會混淆它。

而當您正在調試時,能夠使用編輯器的文本高亮顯示選項有選擇地執行語句的某些部分 - 這是過程代碼中不存在的一種技術。 OTOH,如果把它們分散到視圖中,可能會試圖找到所有的碎片,甚至CTE可能會使這個不方便。

2

我看不到的一個性能提示是使用UNION ALL而不是UNION,除非您故意需要不同的記錄。簡單的UNION將消除需要時間的重複。 UNION ALL不這樣做。

你可以用動態SQL和循環重寫它,但我認爲結果會更糟。如果有足夠的重複代碼來證明動態sql方法的合理性,那麼我想這可能是合理的。

另外,你是否考慮過將存儲過程中的邏輯移出像LINQ之類的東西?對於很多人來說,這不是一種選擇,所以我只是問。

最後一點:抵制修復未破的東西的衝動,讓它看起來更乾淨。如果清理將有助於維護,驗證等,那就去做吧。

3

我打算在這裏出門,根據你給我們的信息說,

這是好,因爲它會得到

+0

還有什麼我可以提供的? – 2009-01-28 21:26:55

+0

@ LFSR-我在談論我們可以從代碼中做出的一般假設。但不,我懷疑更多的信息會有很大的幫助。我認爲這不值得,但它看起來像是有一個業務需求,而目前的數據模型並不適合。重構數據庫'可能'是有序的。 – 2009-01-28 21:34:27

+0

可能是有序的,但不太可能(並且在一個典型的企業系統中不容易想象。) – dkretz 2009-01-28 23:12:24

1

什麼問題?太長?太重複?

有時你會得到醜陋的SQL - 對此你可能做的不多。

我沒有看到任何方式清除它,除非你想使用單獨的視圖,然後將它們結合在一起。

1

我對視圖投了贊成票,這會強加近乎零的開銷(好吧,也許是一個小的編譯時間成本,但應該是全部)。那麼你的特效成爲形式

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

我不知道如果我想任何進一步凝結成的東西,儘管我希望大多數平臺不會容忍它。

0

在動態SQL主題 - 這裏是一個示例 - 不知道它是否更好。好處是你只需要寫一次SELECT列表。

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 
0

如果你所有的過程都是這樣的 - 你可能會遇到一個架構問題。

你對table2的所有調用是否只有一個有用的字段? (因爲聯盟,最終只有一排?)

我總是第二個想到使用參數化動態SQL和/或代碼生成這個工作,甚至使用INFORMATION_SCHEMA動態生成列列表。這不完全是你需要的,但它是一個開始(你可能生成一張數據庫和表格):

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) 
0

根據返回的行數,您最好在選擇上使用UNION ALL,並在其周圍使用選擇不同的查詢。 我以前見過類似的問題,並有兩個不同的風格不同的執行計劃

 
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