13

लंबे प्रश्न के लिए खेद है, लेकिन इसमें सभी एसक्यूएल शामिल हैं जो मैंने परिदृश्य का परीक्षण करने के लिए उपयोग किया है ताकि उम्मीद है कि मैं जो कर रहा हूं उसके बारे में स्पष्ट रूप से यह स्पष्ट कर सकता हूं।एसक्यूएल सर्वर - डायनामिक पिवोट टेबल - एसक्यूएल इंजेक्शन

मैं कुछ गतिशील एसक्यूएल का निर्माण एसक्यूएल सर्वर में पिवट तालिका का निर्माण करने के 2005

नीचे यह करने के लिए कोड है हूँ। विभिन्न चयनों के साथ कच्चे डेटा को ग्रुप BY और PIVOT में मानों का उपयोग करके मूल्यों को दिखाते हुए मैं उन्हें चाहता हूं।

BEGIN TRAN 
--Create the table 
CREATE TABLE #PivotTest 
(
    ColumnA nvarchar(500), 
    ColumnB nvarchar(500), 
    ColumnC int 
) 

--Populate the data 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('A', 'X', 1) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('A', 'Y', 2) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('A', 'Z', 3) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('A', 'X', 4) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('A', 'Y', 5) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('B', 'Z', 6) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('B', 'X', 7) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('B', 'Y', 8) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('B', 'Z', 9) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('C', 'X', 10) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('C', 'Y', 11) 
INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('C', 'Z', 12) 

--The data 
SELECT * FROM #PivotTest 

--Group BY 
SELECT 
    ColumnA, 
    ColumnB, 
    SUM(ColumnC) 
FROM 
    #PivotTest 
GROUP BY 
    ColumnA, 
    ColumnB 

--Manual PIVOT 
SELECT 
    * 
FROM 
    (
     SELECT 
      ColumnA, 
      ColumnB, 
      ColumnC 
     FROM 
      #PivotTest 
    ) DATA 
    PIVOT 
    (
     SUM(DATA.ColumnC) 
    FOR 
     ColumnB 
     IN 
     (
      [X],[Y],[Z] 
     ) 
    ) PVT 

--Dynamic PIVOT 
DECLARE @columns nvarchar(max) 

SELECT 
    @columns = 
    STUFF 
    (
     (
      SELECT DISTINCT 
       ', [' + ColumnB + ']' 
      FROM 
       #PivotTest 
      FOR XML PATH('') 
     ), 1, 1, '' 
    ) 

EXEC 
(' 
    SELECT 
     * 
    FROM 
     (
      SELECT 
       ColumnA, 
       ColumnB, 
       ColumnC 
      FROM 
       #PivotTest 
     ) DATA 
     PIVOT 
     (
      SUM(DATA.ColumnC) 
     FOR 
      ColumnB 
      IN 
      (
       ' + @columns + ' 
      ) 
     ) PVT 
') 

--The data again 
SELECT * FROM #PivotTest 

ROLLBACK 

जब भी मैं कोई गतिशील एसक्यूएल उत्पन्न करता हूं, मैं हमेशा एसक्यूएल इंजेक्शन हमलों के बारे में जानता हूं। इसलिए मैंने अन्य आईएनएसईआरटी कथन के साथ निम्नलिखित पंक्ति को जोड़ा है।

INSERT INTO #PivotTest (ColumnA, ColumnB, ColumnC) VALUES('A', 'FOO])) PVT; DROP TABLE #PivotTest;SELECT ((GETDATE()--', 1) 

जब मैं अब एसक्यूएल, कम होने और निहारना, EXEC हिस्सा चला जाता है #PivotTest तालिका इस प्रकार पिछले चयन असफल।

तो मेरा सवाल यह है कि क्या कोई एसक्यूएल इंजेक्शन हमलों को जोखिम के बिना गतिशील पिवोट करने का तरीका जानता है?

उत्तर

15

हमने आपके उदाहरण के समान काम किया है। हम एसक्यूएल इंजेक्शन के बारे में चिंतित नहीं हैं, क्योंकि हमारे पास डेटा के आधार पर पूर्ण और पूर्ण नियंत्रण है - ईटीएल के माध्यम से हमारे डेटा वेयरहाउस में दुर्भावनापूर्ण कोड प्राप्त नहीं हो सकता है।

कुछ विचार और सलाह:

  • आप nvarcahr साथ (500) कॉलम पिवट करने के लिए आवश्यक है? हमारा वर्चर (25) या न्यूमेरिक्स है, और वहां से हानिकारक कोड को छिपाना मुश्किल होगा।
  • डेटा जांच के बारे में कैसे? ऐसा लगता है कि उन तारों में से एक में "]" चरित्र होता है, यह या तो एक हैक प्रयास या डेटा है जो आपको वैसे भी उड़ा देगा।
  • आपकी सुरक्षा कितनी मजबूत है? क्या सिस्टम लॉक हो गया है कि मैलोरी अपने हैक को अपने डेटाबेस में घुमा नहीं सकता (या तो सीधे या आपके आवेदन के माध्यम से)?

हा। यह कार्य QUOTENAME() को याद रखने के लिए सब कुछ लिखता है। ,

SELECT 
     @columns = 
     STUFF 
     (
       (
         SELECT DISTINCT 
           ', [' + quotename(ColumnB, ']') + ']' 
         FROM 
           #PivotTest 
         FOR XML PATH('') 
       ), 1, 1, '' 
     ) 

यह पिवट (और unpivot) स्थितियों के लिए काम करना चाहिए: एक त्वरित परीक्षण से संकेत मिलता है जो आपके कोड पर ऐसा लगता है कि इतना काम करेगा जोड़ने (आप एक गिरा अस्थायी तालिका एक त्रुटि, नहीं मिलेगा) प्रतीत होता है चूंकि आपको लगभग हमेशा अपने मूल्यों को [ब्रैकेट] करना होता है।

+0

1) मेरा परीक्षण नमूना एक साधारण से एक है। वास्तविक कॉलम nvarchar (अधिकतम) हैं। हमारे पास वर्तमान में कोई डेटा नहीं है और PIVOT के लिए उपयोग किया जाने वाला डेटा शायद ही कभी 100 हो जाएगा, इसलिए मैं इस उदाहरण में मजबूर छंटनी कर सकता हूं! महान विचार। 2) मैं '[' और ']' के बारे में सोच रहा था। मैं डेटा से सभी वर्ग ब्रैकेट को पट्टी करने के लिए प्रेरित हूं और बस इस कार्यक्षमता की सीमा के रूप में है। 3) इस डेटा को जोड़ने वाले एकमात्र लोग "सुपर उपयोगकर्ता" कहलाते हैं, हालांकि, यह मुझे दिमाग की शांति देने के लिए पर्याप्त नहीं है। –

+1

QUOTENAME! पहली बार मैंने इसे देखा है! उत्तम! यह पूरी तरह से समस्या हल करता है। मैं मैन्युअल रूप से QUOTES जोड़ रहा था।अगर मैं इसे हटा देता हूं और इसे QUOTENAME का उपयोग करके करता हूं तो यह उस क्षेत्र के भीतर किसी भी SQL को अक्षम कर देगा! धन्यवाद! –

0

पुनर्रचना के बारे में थोड़ी ...

CREATE PROCEDURE ExecutePivot (
    @TableName sysname, 
    @GroupingColumnName sysname, 
    @AggregateExpression VARCHAR(256), 
    @SelectExpression VARCHAR(256), 
    @TotalColumnName VARCHAR(256) = 'Total', 
    @DefaultNullValue VARCHAR(256) = NULL, 
    @IsExec BIT = 1) 
AS 
BEGIN 
    DECLARE @DistinctGroupedColumnsQuery VARCHAR(MAX); 
    SELECT @DistinctGroupedColumnsQuery = CONCAT('SELECT DISTINCT ',@GroupingColumnName,' FROM ',@TableName,';'); 
    DECLARE @DistinctGroupedColumnsResult TABLE ([row] VARCHAR(MAX)); 
    INSERT INTO @DistinctGroupedColumnsResult EXEC(@DistinctGroupedColumnsQuery); 

    DECLARE @GroupedColumns VARCHAR(MAX); 
    SELECT @GroupedColumns = STUFF ((SELECT DISTINCT CONCAT(', ',QUOTENAME([row])) FROM @DistinctGroupedColumnsResult FOR XML PATH('')), 1, 1, ''); 

    DECLARE @GroupedColumnsNullReplaced VARCHAR(MAX); 
    IF(@DefaultNullValue IS NOT NULL) 
     SELECT @GroupedColumnsNullReplaced = STUFF ((SELECT DISTINCT CONCAT(', ISNULL(',QUOTENAME([row]),',',@DefaultNullValue,') AS ',QUOTENAME([row])) FROM @DistinctGroupedColumnsResult FOR XML PATH('')), 1, 1, ''); 
    ELSE 
     SELECT @[email protected]; 

    DECLARE @ResultExpr VARCHAR(MAX) = CONCAT(' 
     ; WITH cte AS 
     (
      SELECT ',@SelectExpression,', ',@GroupedColumns,' 
      FROM ',@TableName,' 
      PIVOT (',@AggregateExpression,' FOR ',@GroupingColumnName,' IN (',@GroupedColumns,')) as p 
     ) 
     , cte2 AS 
     (
      SELECT ',@SelectExpression,', ',@GroupedColumnsNullReplaced,' 
      FROM cte 
     ) 
     SELECT ',@SelectExpression,', ',REPLACE(@GroupedColumns,',','+'),' AS ',@TotalColumnName,', ',@GroupedColumns,' 
     FROM cte2; 
     '); 

    IF(@IsExec = 1) EXEC(@ResultExpr); 
    ELSE SELECT @ResultExpr; 
END; 

प्रयोग उदाहरण:

select schema_id, type_desc, 1 as Item 
    into PivotTest 
from sys.objects; 

EXEC ExecutePivot 'PivotTest','type_desc','SUM(Item)','schema_id','[Total Items]','0',1; 
संबंधित मुद्दे