SQL SERVER 實現多行轉多列

来源:https://www.cnblogs.com/tohert/archive/2019/08/01/11283723.html
-Advertisement-
Play Games

有這樣一個需求,一個表單主表,一個擴展列表,查詢的時候要把擴展列表中的多行轉成主表多列。 比如 dt_zhubiao [主表] dt_kuozhanbiao [擴展表] 查詢時,會根據dt_zhubiao表的type來查詢,type欄位一樣時,dt_kuozhanbiao表條數和name都會一致,v ...


有這樣一個需求,一個表單主表,一個擴展列表,查詢的時候要把擴展列表中的多行轉成主表多列。

比如

dt_zhubiao [主表]

id type title
1 1 表單1-1
2 1 表單1-2
3 2 表單2-1
4 2 表單2-2

dt_kuozhanbiao [擴展表]

id formid name title value
1 1 ext_a 工齡 18
2 1 ext_b 職稱 副級
3 2 ext_a 工齡 20
4 2 ext_b 職稱 正級
5 3 ext_2a 欄位1 值1
6 3 ext_2b 欄位2 值2
7 3 ext_2c 欄位3 值3
8 4 ext_2a 欄位1 值21
9 4 ext_2b 欄位2 值22
10 4 ext_2c 欄位3 值23

查詢時,會根據dt_zhubiao表的type來查詢,type欄位一樣時,dt_kuozhanbiao表條數和name都會一致,value不一致。

想要的結果如下:

查詢type=1時,select * from dt_zhubiao where type = 1 ... 

id type title ext_a ext_b
1 1 表單1-1 18 副級
2 1 表單1-2 20 正級

查詢type=2時,select * from dt_zhubiao where type =2 ...

id type title ext_2a ext_2b ext_2c
3 2 表單2-1 值1 值2 值3
4 2 表單2-2 值21 值22 值23

 

那麼問題來了,基於 select * from dt_zhubiao where type = ? 基礎sql語句,如何生成這種查詢結果 ? 

這個問題應該多用於動態表單,之前自己嘗試過join 、union去解決,都總差那麼點意思。 -:)

後面去多個論壇發帖挨個問了個遍,終於尋到解決辦法了。SQL 代碼如下:

--測試數據
if not object_id(N'Tempdb..#主表') is null
    drop table #主表
Go
Create table #主表([id] int,[type] int,[title] nvarchar(25))
Insert #主表
select 1,1,N'表單1-1' union all
select 2,1,N'表單1-2' union all
select 3,2,N'表單2-1' union all
select 4,2,N'表單2-2'
GO
if not object_id(N'Tempdb..#擴展表') is null
    drop table #擴展表
Go
Create table #擴展表([id] int,[formid] int,[name] nvarchar(26),[title] nvarchar(23),[value] nvarchar(22))
Insert #擴展表
select 1,1,N'ext_a',N'工齡',N'18' union all
select 2,1,N'ext_b',N'職稱',N'副級' union all
select 3,2,N'ext_1',N'工齡',N'18' union all
select 4,2,N'ext_b',N'職稱',N'正級' union all
select 5,3,N'ext_2a',N'欄位1',N'值1' union all
select 6,3,N'ext_2b',N'欄位2',N'值2' union all
select 7,3,N'ext_2c',N'欄位3',N'值3'union all
select 8,4,N'ext_2a',N'欄位1',N'值1' union all
select 9,4,N'ext_2b',N'欄位2',N'值2' union all
select 10,4,N'ext_2c',N'欄位3',N'值3'
Go
--測試數據結束
DECLARE @sql VARCHAR(MAX)
SET @sql = 'select #主表.id,#主表.type,#主表.title'
SELECT  @sql = @sql + ',max(case name when ''' + name
        + ''' then [value] else null end)[' + name + ']'
FROM    ( Select DISTINCT name from #擴展表 JOIN #主表 ON  formid IN (SELECT id FROM #主表 WHERE type=2)
        ) a
SET @sql = @sql
    + ' from #擴展表 JOIN #主表 ON  formid =#主表.id  WHERE type=2 group by #主表.id,#主表.type,#主表.title'
EXEC(@sql) 

至此已經解決了我的問題,但是對於實際的項目運用還是缺少點什麼,比如 分頁、條件篩選。那麼得在此基礎上稍微修改一下,這個簡單我自己會做了  -:) 。

DECLARE @sql VARCHAR(MAX)
SET @sql = 'with tb as (select ROW_NUMBER() OVER(Order by  #主表.id ) AS rindex,#主表.id,#主表.type,#主表.title'
SELECT  @sql = @sql + ',max(case name when ''' + name
        + ''' then [value] else null end)[' + name + ']'
FROM    ( Select DISTINCT name from #擴展表 JOIN #主表 ON  formid IN (SELECT id FROM #主表 WHERE type=2)
        ) a
SET @sql = @sql
    + ' from #擴展表 JOIN #主表 ON  formid =#主表.id  WHERE type=2 group by #主表.id,#主表.type,#主表.title); select * from tb where ext_2b =''值1'' and rindex between  1 and 10 '  --拼接with 及查詢條件
EXEC(@sql) 

到這自我感覺應該差不多了,再改改做成個存儲過程應該可以用了,但是吧,想著用程式也去實現一遍,看看哪種實行起來更方便 -:) 

程式實現兩種思路,一種組裝table:先結合分頁、條件篩選等查出需要的主表數據集得到一個datatable,然後給datatable動態去添加對應列,然後迴圈去賦值(這種情況就無法實現針對擴展欄位進行排序)。

DataTable tb = DbHelperSQL.Query("with tb as (select row_number over(order by #主表.id) as rindex,* from #主表 where id in (select formid from #擴展表 where value ='值2') adn type=2 );select * from tb where rindex between 1 and 10").Tables[0];
var ar = new System.Collections.ArrayList();
foreach (DataRow crow in DbHelperSQL.Query("select name from #擴展表 where formid in (select id from #主表 where type = 2)").Tables[0].Rows) {
    ar.Add(crow[0]);
    tb.Columns.Add(crow[0].ToString(), typeof(string));
}
//這裡可以一次性載入tb數據集中包含的所有#擴展表數據,然後在記憶體中進行操作賦值,如下迴圈查詢資料庫賦值只是為了寫的方便
for (var i =0; i <tb.Rows.Count;i++) {
    var formid = tb.Rows[i]["id"];
    foreach (var ari in ar) {
        tb.Rows[i][ari.ToString()] = DbHelperSQL.GetSingle(string.Format("select value from #臨時表 where formid ={0} and name ='{1}'",formid,ari));
    }
 }
 return tb;

第二種就是組裝SQL語句啦,但是不在程式中組裝之前的@sql字元串,但是還是參考之前的SQL代碼思路,然後轉成程式代碼思路。在之前SQL實現的代碼中,最後的exec(@sql)前一行加上列印@sql的語句,就會得到最後執行的sql語句

select #主表.id,#主表.type,#主表.title
,max(case name when 'ext_2a' then [value] else null end)[ext_2a]
,max(case name when 'ext_2b' then [value] else null end)[ext_2b]
,max(case name when 'ext_2c' then [value] else null end)[ext_2c]
 from #擴展表 JOIN #主表 ON  formid =#主表.id  WHERE type=2 group by #主表.id,#主表.type,#主表.title

基於這個SQL語句用程式去拼接最終的SQL語句執行(包括分頁、條件篩選)。

string sql=" with tb as (select row_number over(order by #主表.id) rindex, #主表.id,#主表.type,#主表.title";
foreach (DataRow crow in DbHelperSQL.Query("select name from #擴展表 where formid in (select id from #主表 where type = 2) group by name").Tables[0].Rows) {
    sql +=",max(case name when '"+crow["name"]+"' then [value] else null end) "+crow["name"];
}
sql+=" from #擴展表 join #主表 on formid = #主表.id where type = 2 group by #主表.id,#主表.type,#主表.title); select * from tb where ext_2a ='值1' and rindex between 1 and 10 ";
return DbHelperSQL.Query(sql).Tables[0];
//此處單純的SQL語句拼接,也可以再次優化實現動態參數化。

這種情況是可以實現所有的列都能進行排序。 目前來講,還只是去實現這個功能,還沒有考慮性能優化之類的。

論壇原咨詢帖:https://bbs.csdn.net/topics/392999794 。 記於此以作備份,好記性不如爛筆頭。 -:)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linux網路——查看網路連接情況的命令 摘要:本文主要學習了Linux中用來查看網路連接情況的命令。 hostname命令 hostname命令用於顯示和設置系統的主機名稱,設置只是臨時生效,永久生效需要更改配置文件。 基本語法 修改主機名: 查看系統信息: 選項說明 使用舉例 ping命令 pi ...
  • 前言:無人機和人工智慧現在是非常熱門的話題,將兩者結合起來是一個比較好的創意,本文介紹一種可行的解決方案來實現基於視覺感知的跟蹤無人機。從零開始搭建無人機系統工作量和難度(以及錢)都是非常大的,所以在無人機系統的選擇上,選用正點原子開發的開源演算法無人機Minifly四軸和攝像頭。視覺感知模塊(目標檢 ...
  • 完全零基礎在Linux中安裝 JDK 總體思路:先確定沒有Java程式了 — 然後創建相應路徑文件夾 — 下載JDK — 解壓到當前路徑 — 自定義文件名稱 — 配置環境變數 — 檢查是否安裝成功 第一步 進入到root編程環境 第二步 查看已安裝的Java程式 我有的Java程式如下(這裡因人而異 ...
  • 資料庫MySQL學習筆記 [TOC] 寫在前面 學習鏈接: "資料庫 MySQL 視頻教程全集" MySQL引入 資料庫的好處 1. 持久化數據到本地 2. 可以實現結構化查詢,方便管理 資料庫的相關概念 DB:資料庫(database):存儲數據的“倉庫”,它保存了一系列有組織的數據。 DBMS: ...
  • 某日閑餘時間看到一篇介紹Gridea博客平臺的文章,大概看了一下覺得此平臺還不錯,隨即自己進入Gridea官網瞅了瞅。哇,這搭建過程也太簡單了吧,比Hexo博客搭建要容易很多,而且還有後臺管理客戶端,很適合小白用戶入門。最重要的是不用自己購買功能變數名稱!可以直接與GitHub或Coding配合展示頁面。下 ...
  • 前言: 前面幾篇文章,我們介紹了MySQL的基礎概念及邏輯架構。相信你現在應該有了自己的一套MySQL環境,接下來我們就可以開始練習MySQL了。本文將從MySQL最基礎的語句出發,為你展示出創建及修改不同對象應該使用的標準語句。 1.創建資料庫 創建資料庫的官方標準語法為: 其中{}中的內容為多選 ...
  • xtrabackup是一個MySQL備份還原的常用工具,實際使用過程應該都是shell或者python封裝的自動化腳本,尤其是備份。對還原來說,對於基於完整和增量備份的還原,還原差異備份需要指定增量備份等等一系列容易出錯的手工操作,以及binlog的還原等,如果純手工操作的話非常麻煩。即便是你記性非 ...
  • //2019/7/31 18:41:14掐指一算應該resore完了呀,是不是天熱想罷工?不過已經差不多30個小時了無意間一查 tail -500f /var/log/messages 發現有些“more than 120 seconds|hung_task_timeout_secs”,還有寫ker ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...