ฉันจะสร้างคอลัมน์แทนแบบไดนามิกได้อย่างไร


10

ฉันมีตาราง (ไม่ได้ออกแบบโดยฉัน) ซึ่งมี 20 คอลัมน์ชื่อแตกต่างกัน นั่นคือขึ้นอยู่กับชนิดของระเบียนที่คุณกำลังดูชื่อที่เกี่ยวข้องของคอลัมน์สามารถเปลี่ยนแปลงได้

ชื่อคอลัมน์ที่เป็นไปได้จะถูกเก็บไว้ในอีกตารางหนึ่งซึ่งฉันสามารถสืบค้นได้ง่ายมาก

ดังนั้นข้อความค้นหาที่ฉันกำลังมองหาจะเป็นดังนี้:

SELECT Col1 AS (SELECT ColName FROM Names WHERE ColNum = 1 and Type = @Type),
       Col2 AS (SELECT ColName FROM Names WHERE ColNum = 2 and Type = @Type)
FROM   Tbl1 
WHERE  Type = @Type

เห็นได้ชัดว่าใช้งานไม่ได้ดังนั้นฉันจะได้ผลลัพธ์ที่คล้ายกันได้อย่างไร

' ฉันได้ลองสร้างสตริงข้อความค้นหาแล้วEXECUTEค่อยส่งคืน แต่ก็แค่คืน "Command (s) เสร็จสมบูรณ์แล้ว" และดูเหมือนจะไม่ส่งคืน rowset ปรากฎว่าฉันใช้แบบสอบถามที่ไม่ถูกต้องเพื่อสร้างไดนามิก SQL และเช่นนั้นสร้างสตริงว่างเปล่า SQL Server ดำเนินการสตริงว่างอย่างถูกต้องอย่างแน่นอน

โปรดทราบว่าเหตุผลที่ฉันต้องการสิ่งนี้เกิดขึ้นแทนที่จะเขียนโค้ดชื่อคอลัมน์ยากเพียงอย่างเดียวคือชื่อคอลัมน์นั้นผู้ใช้สามารถกำหนดค่าได้


1
จะเกิดอะไรขึ้นถ้าคุณพิมพ์สตริงข้อความค้นหาคัดลอก / วางในหน้าต่างแบบสอบถามใหม่และดำเนินการที่นั่น
DenisT

"ผู้ใช้กำหนดค่าได้" หมายถึงมีหลายร้อยหรือหลายพันประเภทและ / หรือชื่อแทนถูกเปลี่ยนบ่อยๆ? หากชื่อแทนมีความเสถียรพอสมควรฉันขอแนะนำให้สร้างชุดของมุมมอง
Jon of All Trades

@ DenisT, มันจะไม่แสดงผลอะไรออกไป, ซึ่งอาจบ่งบอกว่ามีบางอย่างผิดปกติเช่นกัน ขอบคุณสำหรับความเป็นผู้นำ
Hotchips

@JonofAllTrades โชคไม่ดีที่ในขณะที่พวกเขาค่อนข้างมีเสถียรภาพมันเป็นส่วนหนึ่งของข้อมูลจำเพาะที่เมื่อผู้ใช้เปลี่ยนแปลงบางสิ่งในซอฟต์แวร์สิ่งนั้นจะต้องเปลี่ยนแปลงในรายงานด้วย
Hotchips

@DenisT ปรากฎว่าแบบสอบถามย่อยของฉันที่ใช้ในการสร้าง SQL แบบไดนามิกไม่ถูกต้องและส่งคืนชุด null ดังนั้น SQL Server จึงส่งคืนเคียวรีเปล่าซึ่งมันดำเนินการโดยสมบูรณ์ ขอบคุณสำหรับการชี้ให้เห็นคำสั่ง PRINT
Hotchips

คำตอบ:


12

ลองรหัสต่อไปนี้:

CREATE TABLE #Names
(
    [Type] VARCHAR(50),
    ColNum SMALLINT,
    ColName VARCHAR(50),
    ColDataType VARCHAR(20)
)

INSERT  INTO #Names VALUES
('Customer', 1, 'CustomerID', 'INT'),
('Customer', 2, 'CustomerName', 'VARCHAR(50)'),
('Customer', 3, 'CustomerJoinDate', 'DATE'),
('Customer', 4, 'CustomerBirthDate', 'DATE'),
('Account', 1, 'AccountID', 'INT'),
('Account', 2, 'AccountName', 'VARCHAR(50)'),
('Account', 3, 'AccountOpenDate', 'DATE'),
('CustomerAccount', 1, 'CustomerID', 'INT'),
('CustomerAccount', 2, 'AccountID', 'INT'),
('CustomerAccount', 3, 'RelationshipSequence', 'TINYINT')


CREATE TABLE #Data
(
    [Type] VARCHAR(50),
    Col1 VARCHAR(50),
    Col2 VARCHAR(50),
    Col3 VARCHAR(50),
    Col4 VARCHAR(50),
    Col5 VARCHAR(50),
    Col6 VARCHAR(50),
    Col7 VARCHAR(50)
)

INSERT  INTO #Data VALUES
('Customer', '1', 'Mr John Smith', '2005-05-20', '1980-11-15', NULL, NULL, NULL),
('Customer', '2', 'Mrs Hayley Jones', '2009-10-10', '1973-04-03', NULL, NULL, NULL),
('Customer', '3', 'ACME Manufacturing Ltd', '2012-12-01', NULL, NULL, NULL, NULL),
('Customer', '4', 'Mr Michael Crocker', '2014-01-13', '1957-01-23', NULL, NULL, NULL),
('Account', '1', 'Smith-Jones Cheque Acct', '2005-05-25', NULL, NULL, NULL, NULL),
('Account', '2', 'ACME Business Acct', '2012-12-01', NULL, NULL, NULL, NULL),
('Account', '3', 'ACME Social Club', '2013-02-10', NULL, NULL, NULL, NULL),
('Account', '4', 'Crocker Tipping Fund', '2014-01-14', NULL, NULL, NULL, NULL),
('CustomerAccount', '1', '1', '1', NULL, NULL, NULL, NULL),
('CustomerAccount', '2', '1', '2', NULL, NULL, NULL, NULL),
('CustomerAccount', '2', '3', '2', NULL, NULL, NULL, NULL),
('CustomerAccount', '3', '2', '1', NULL, NULL, NULL, NULL),
('CustomerAccount', '3', '3', '1', NULL, NULL, NULL, NULL),
('CustomerAccount', '4', '2', '2', NULL, NULL, NULL, NULL),
('CustomerAccount', '4', '4', '1', NULL, NULL, NULL, NULL)


DECLARE @Type VARCHAR(50) = 'Account' -- Or Customer, or CustomerAccount

DECLARE @SQLText NVARCHAR(MAX) = ''

SELECT  @SQLText += 'SELECT '

SELECT  @SQLText += ( -- Add in column list, with dynamic column names.
                SELECT  'CONVERT(' + ColDataType + ', Col' + CONVERT(VARCHAR, ColNum) + ') AS [' + ColName + '],'
                FROM    #Names
                WHERE   [Type] = @Type FOR XML PATH('')
            )

SELECT  @SQLText = LEFT(@SQLText, LEN(@SQLText) - 1) + ' ' -- Remove trailing comma

SELECT  @SQLText += 'FROM #Data WHERE [Type] = ''' + @Type + ''''

PRINT   @SQLText
EXEC    sp_executesql @SQLText

ส่งคืนคำสั่ง SELECT: SELECT CONVERT(INT, Col1) AS [AccountID],CONVERT(VARCHAR(50), Col2) AS [AccountName],CONVERT(DATE, Col3) AS [AccountOpenDate] FROM #Data WHERE [Type] = 'Account'


การใช้ dynamic SQL เป็นคำตอบที่ถูกต้องเนื่องจากคำถามนั้นถามว่าจะทำอย่างไรกับ SQL มันเป็นสิ่งที่ฉันพยายามทำ แต่ไม่ถูกต้อง
Hotchips

จำไว้ว่าถ้าคุณยอมรับการป้อนข้อมูลของผู้ใช้และใช้มันในการสร้างแบบไดนามิก SQL แล้วคุณจริงๆจริงๆจะต้องมีความกังวลเกี่ยวกับการฉีด SQL และฆ่าเชื้อปัจจัยการผลิต bobby-tables.com
Jonathan Van Matre

@JonathanVanMatre อย่างแน่นอน โชคดีที่นี่มีไว้สำหรับใช้ภายในเท่านั้นและอินพุตทั้งหมดได้รับการฆ่าเชื้อแล้วโดยแอป
Hotchips

7

สิ่งนี้ฟังดูยอดเยี่ยมสำหรับโซลูชันการแสดงผลส่วนหน้า Query 1 จะดึงข้อมูลของคุณ Query 2 จะดึงชื่อคอลัมน์กลับมาและในรหัสเมื่อคุณสร้างโครงสร้างใด ๆ ที่คุณเคยใช้ในการแสดงคุณตั้งค่าส่วนหัวจากแบบสอบถามที่สอง

ในขณะที่วิธีบริสุทธิ์ของ SQL อาจเป็นไปได้มันจะเป็น SQL แบบไดนามิกและการบำรุงรักษารหัสจะเป็นฝันร้าย

นอกจากนี้คุณอาจกำลังมองหาsp_executesqlและไม่เพียง แต่EXECUTE N'Query String'ที่อาจแก้ไขปัญหาของคำสั่งของคุณเสร็จเรียบร้อยแล้ว


ฉันเห็นด้วยและฉันสามารถทำสิ่งนี้ได้อย่างแน่นอนใน SSRS แต่ฉันไม่สามารถทำได้ในซอฟต์แวร์การรายงานอื่นที่ฉันใช้อยู่ในขณะนี้
Hotchips
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.