Sql-Server

SQL 連接到相同的表組合

  • December 21, 2018

我想將第一個表加入相同的連接組合:X、Y、Z。第一個表可以是不同的表類型,但它們都連接到同一組表。表 A 可能有 8 列不同數據類型,表 B 可能有 15 列不同表類型。我如何在不重複的情況下為此編碼?這些表稍後會連接到其他表。如果第一個表總是不同的,我將如何將這些連接組合保存在視圖或表函式等中?

我們有 100 多個這樣的查詢,最終可能希望添加更多表來保存 XYZ 組合,未來可能會增加 7 個。STUVXYZ。問題變得更多的是程式碼的多功能性。想在 1 個位置進行更改,而不是 100 個不同的查詢。

注意:表 X、Y、Z 具有不同的列和數據類型,除了 ProductId 和 ProductType。

Select a.*, x.*,y.*,z.* 
from TableA a
left join DimShelf x
 on b.ProductId = x.ProductId 
 and b.ProductTypeId = x.ProductTypeId -- 1
left join DimDesk y
 on b.ProductId = y.ProductId 
 and b.ProductTypeId = y.ProductTypeId -- 2
left join DimCouch
 on b.ProductId = z.ProductId 
 and b.ProductTypeId = z.ProductTypeId -- 3
left join other items of variation with where clauses at end...

Select b.*, x.*,y.*,z.* 
from Tableb b
left join DimShelf x
 on b.ProductId = x.ProductId 
 and b.ProductTypeId = x.ProductTypeId -- 1
left join DimDesk y
 on b.ProductId = y.ProductId 
 and b.ProductTypeId = y.ProductTypeId -- 2
left join DimCouch
 on b.ProductId = z.ProductId 
 and b.ProductTypeId = z.ProductTypeId -- 3
left join other items of variation with where clauses at end...




create table dbo.DimChair
(
   DimChairId int primary key identity(1,1),
   ProductTypeid int,
   ProductId int,
   Color varchar(55),
   LegNumber int
)

create table dbo.DimShelf
(
   DimShelfId int primary key identity(1,1),
   ProductTypeid int,
   ProductId int,
   Length float,
   Height float,
   NumberofShelves varchar(55)
)

create table dbo.DimCouch
(
   DimCouchId int primary key identity(1,1),
   ProductTypeid int,
   ProductId int,
   FabricType varchar(255),
)

正如@Akina 所建議的,最好只編寫一個查詢,將所需的表連接到連接公共表的視圖。通過這種方式,我們可能能夠很好地優化和內聯視圖。

我們需要注意,對於所有 3 個連接,我們使用從連接到每個表的表中的相同值。因此,我們應該能夠創建一個視圖,該視圖具有可加入的整組值 {ProductID, ProductType}。

我將假設並非所有有效值都必然存在於每個表中,因此我們不能只將其他表連接到X表中;它甚至可能沒有我們最終想要的價值。因此,我們首先需要所有表中的所有可能值。

CREATE VIEW AllThings AS
WITH AllPossibleValues AS (
 SELECT ProductID, ProductType
 FROM DimShelf 
 UNION 
 SELECT ProductID, ProductType
 FROM DimDesk
 UNION 
 SELECT ProductID, ProductType
 FROM DimCouch
)
SELECT 
 b.ProductID,
 b.ProductType,
 x.... -- All columns you need from x
 y.... -- All columns you need from y
 x.... -- All columns you need from z
FROM AllPossibleValues AS b
LEFT JOIN DimShelf x
 ON b.ProductId = x.ProductId 
 AND b.ProductTypeId = x.ProductTypeId -- 1
LEFT JOIN DimDesk y
 ON b.ProductId = y.ProductId 
 AND b.ProductTypeId = y.ProductTypeId -- 2
LEFT JOIN DimCouch
 on b.ProductId = z.ProductId 
 and b.ProductTypeId = z.ProductTypeId -- 3
;

請注意,不建議SELECT *與視圖定義中的任何表一起使用 - 這意味著它將選擇所有列,但實際上它只選擇視圖創建/修改時存在的所有列。因此,最好明確列舉列。這確實會導致冗長的查詢定義,但正如@Akina 正確指出的那樣,這不一定會損害優化。

此外,如果您發現性能有問題,您可能需要將謂詞下推到 CTE,這需要使用表值函式來傳遞參數。與此類似的東西:

CREATE FUNCTION AllThingsParameterized (
 @ProductID int,
 @ProductType varchar(50)
) AS RETURNS TABLE
RETURN
WITH AllPossibleValues AS (
 SELECT ProductId, ProductType
 FROM DimCouch AS x
 WHERE ProductID = @ProductID
   AND ProductType = @ProductType
 UNION
 ....
) ...

但是,此變體僅適用於ProductID&的一個值ProductType;如果您需要一組ProductID& ProductType,那麼您可能需要考慮使用表值參數,這可能會使設置更加複雜。

請注意,如果視圖在另一個視圖中使用,您可能會否定內聯的好處,因為最終語句可能變得過於復雜,優化器無法有效優化。如果這是您的典型場景,您實際上可能會更好地從儲存過程生成臨時表結果並將表連接到該表。

您可以創建一個包含所有左連接的視圖,然後左連接給定視圖到您的源表。您可以使用動態 SQL 參數化表源選擇。

這部分:

left joinTableX x
 on a.ProductId = x.ProductId
 and a.ProductTypeId = x.ProductTypeId -- 1
left join TableY y
 on a.ProductId = y.ProductId 
 and a.ProductTypeId = y.ProductTypeId -- 2
left join TableZ z
 on a.ProductId = z.ProductId
 and a.ProductTypeId = z.ProductTypeId -- 3
left join other items of variation with where clauses at end...

必須重寫為這樣的視圖定義:

create view view_you_need as
select
   all relevant columns
   from TableX x
   left join TableY y
     on x.ProductId = y.ProductId 
     and x.ProductTypeId = y.ProductTypeId -- 2
   left join TableZ z
     on x.ProductId = z.ProductId
     and x.ProductTypeId = z.ProductTypeId -- 3
   left join other items of variation with where clauses at end...

然後,您可以從第一個表(更改的表)中選擇並左連接到 view_you_need 視圖。為了動態更改源表,可以使用動態 SQL,如下所示:

declare @sourcetable varchar(100) = 'TableB';
declare @sql nvarchar(max);

select @sql = 
'select
   all relevant columns
from ' + @sourcetable + 
' left join view_you_need 
on etc etc';

exec(@sql);

抱歉,我有點忙,因此是虛擬碼。希望至少有一點幫助。祝你好運。

引用自:https://dba.stackexchange.com/questions/224618