日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

SQL Server里PIVOT运算符的”红颜祸水“

發布時間:2023/12/20 数据库 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SQL Server里PIVOT运算符的”红颜祸水“ 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

SQL Server里PIVOT運算符背后的基本思想是在T-SQL查詢期間,你可以旋轉行為列。運算符本身是SQL Server 2005后引入的,主要用在基于建立在實體屬性值模型(Entity Attribute Value model (EAV))原則上的數據庫。EAM模型背后的想法是你可以擴展數據庫實體,而不需要進行數據庫架構的修改。因此EAV模型存儲實體的所有屬性以鍵/值對存儲在一個表里。我們來看下面一個簡單的鍵/值對模型的表。?

CREATE TABLE EAVTable (RecordID INT NOT NULL,Element CHAR(100) NOT NULL,Value SQL_VARIANT NOT NULL,PRIMARY KEY (RecordID, Element) ) GO-- Insert some records INSERT INTO EAVTable (RecordID, Element, Value) VALUES (1, 'FirstName', 'Woody'), (1, 'LastName', 'Tu'), (1, 'City', 'Linhai'), (1, 'Country', 'China'), (2, 'FirstName', 'Bill'), (2, 'LastName', 'Gates'), (2, 'City', 'Seattle'), (2, 'Country', 'USA') GO

如你所見,我們插入2個數據庫實體到表里,每個實體包含多個屬性。在表里每個屬性只是額外的記錄。如果你像擴展實體更多的屬性,你只插入額外的記錄到表里,而沒有必要進行數據庫架構修改——這就是開放數據庫架構的“威力”……

查詢這樣的EAV表顯然很困難,因為你處理的是平鍵/值對的數據結構。因此你要旋轉表內容,行旋轉為列。你可以進行用自帶的PIVOT運算符進行這個旋轉,或者通過傳統的CASE表達式進行純手工來實現。在我們進入PIVOT細節前,我想給你展示下通過手工使用T-SQL和一些CASE表達式來實現。如果你手工進行旋轉,你的T-SQL查詢需要實現3個階段:?

  • 分組階段(Grouping Phase)
  • 攤開階段(Spreading Phase)
  • 聚合階段(Aggregation Phase)
  • 分組階段(Grouping Phase)我們壓縮我們的EAV表為不同的數據庫實體。在這里我們在RecordID列進行一個GROUP BY。在第2階段的,攤開階段(Spreading Phase),我們使用多個CASE表達式來旋轉行為列。最后在聚合階段(Aggregation Phase)我們使用MAX表達式來為每個行和列返回不同值。我們來看下列T-SQL代碼。

    1 -- Pivot the data with a handwritten T-SQL statement. 2 -- Make sure you have an index defined on the grouping column. 3 SELECT 4 RecordID, 5 -- Spreading and aggregation phase 6 MAX(CASE WHEN Element = 'FirstName' THEN Value END) AS 'FirstName', 7 MAX(CASE WHEN Element = 'LastName' THEN Value END) AS 'LastName', 8 MAX(CASE WHEN Element = 'City' THEN Value END) AS 'City', 9 MAX(CASE WHEN Element = 'Country' THEN Value END) AS 'Country' 10 FROM EAVTable 11 GROUP BY RecordID -- Grouping phase 12 GO

    從代碼里可以看到,很容易區分每個階段,還有它們如何映射到T-SQL查詢。下圖給你展示了查詢結果,最后我們把行轉為了列。

    PIVOT運算符

    自SQL Server 2005起(差不多10年前了!),微軟在T-SQL里引入PIVOT運算符。使用那個運算符你可以進行同樣的轉換(行到列),只要一個原生運算符即可。聽起來很簡單,很有前景,不是么?下列代碼顯示了使用原生PIVOT運算符進行同樣的轉換。?

    1 -- Perform the same query with the native PIVOT operator. 2 -- The grouping column is not specified explicitly, it's the remaining column 3 -- that is not referenced in the spreading and aggregation elements. 4 SELECT 5 RecordID, 6 FirstName, 7 LastName, 8 City, 9 Country 10 FROM EAVTable 11 PIVOT(MAX(Value) FOR Element IN (FirstName, LastName, City, Country)) AS t 12 GO

    當你執行那個查詢時,你會收到和剛才圖片一樣的結果。但當你看PIVOT運算符語法時,和手動方法相比,你會看到一個很大的區別:

    你只能指定分攤和聚合元素!不能明確定義分組元素!

    分組元素是你在PIVOT運算符里沒有引用的剩下列。在我們的例子里,我們沒有在PIVOT運算符里沒有引用RecordID列,因此這個列在分組階段(Grouping Phase)被使用。如果我們隨后修改數據庫架構,這會帶來有趣的副作用,例如對基本表增加額外列:

    1 -- Add a new column to the table 2 ALTER TABLE EAVTable ADD SomeData CHAR(1) 3 GO

    然后我們對其賦值:

    1 UPDATE dbo.EAVTable SET SomeData=LEFT(CAST(Value AS VARCHAR(1)),1)

    現在當你執行用PIVOIT運算符的同個查詢時(在那somedata列都有非NULL值),你會拿回完全不同的結果,因為排序階段現在是在RecordIDSomeData列(我們剛加的)上。

    相比如果我們重新執行我們剛開始寫的手工T-SQL查詢會發生什么。它還是返回同樣正確的結果。這是在SQL Server里,PIVOT運算符的其中一個最大的副作用:分組元素不能明確定義。為了克服這個問題,最佳實踐是使用只返回需要列的表表達式。使用這個方法,如果你隨后修改表架構還是沒有問題,因從表表達式默認情況下額外的列還是沒有返回。我們來看下列的代碼:

    1 -- Use a table expression to state explicitly which columns you want to 2 -- return from the base table. Therefore you can always control on which 3 -- columns the PIVOT operator is performing the grouping. 4 SELECT 5 RecordID, 6 FirstName, 7 LastName, 8 City, 9 Country 10 FROM 11 ( 12 -- Table Expression 13 SELECT RecordID, Element, Value FROM EAVTable 14 ) AS t 15 PIVOT(MAX(Value) FOR Element IN (FirstName, LastName, City, Country)) AS t1 16 GO

    從代碼里可以看到,我通過一個表表達式輸送給PIVOT運算符。而且在表表達式里,你從表里只選擇需要的列。這就意味著以后你可以修改表架構也會破壞PIVOT查詢的結果。

    小結

    我希望這篇文章已向你展示了在SQL Server里,為什么PIVOT運算符是非常危險的。這個語法本身帶來了非常高效的代碼,但作為副作用你不能直接指定分組元素。因次你應該確保使用一個表表達式來定義輸送給PIVOT運算符的列來保證給出結果的確定性。



    本文轉自Woodytu博客園博客,原文鏈接:http://www.cnblogs.com/woodytu/p/4681759.html,如需轉載請自行聯系原作者

    總結

    以上是生活随笔為你收集整理的SQL Server里PIVOT运算符的”红颜祸水“的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。