मैं टी-एसक्यूएल का उपयोग कर रहा हूं। लक्ष्य एकाधिक फ़ाइलों को डेटाबेस में सम्मिलित करना है। अगर मैं लूप के बिना उपयोग कर रहा हूं, तो यह ठीक काम कर रहा है।

लूप में, मुझे हमेशा यह त्रुटि मिलती है:

@InputXML घोषित किया जाना चाहिए

मेरा कोड:

IF OBJECT_ID('TEMPDB..#TEMP_FILES') IS NOT NULL 
    DROP TABLE #TEMP_FILES

CREATE TABLE #TEMP_FILES
(
    FileName VARCHAR(MAX),
    DEPTH VARCHAR(MAX),
    [FILE] VARCHAR(MAX)
)
 
INSERT INTO #TEMP_FILES
    EXEC master.dbo.xp_DirTree '\\MyServer\MyFolder\',1,1
    
DELETE FROM #TEMP_FILES WHERE RIGHT(FileName,4) != '.XML'
    
--
SET QUOTED_IDENTIFIER ON 
GO
    
TRUNCATE Table MyTable2

DECLARE @InputXML XML
DECLARE @FILENAME VARCHAR(MAX),@SQL VARCHAR(MAX)
    
WHILE EXISTS(SELECT * FROM #TEMP_FILES)
BEGIN
    SET @FILENAME = (SELECT TOP 1 FileName FROM #TEMP_FILES)
    SET @sql = 'SELECT @InputXML = CAST(x AS XML) FROM OPENROWSET(BULK \\MyServer\MyFolder\'''+ @FILENAME +''', SINGLE_BLOB) AS T(x)
       
    INSERT INTO MyTable2 ([id],[version], [name], [listId], [listCode])
        SELECT 
            product.value(''(@id)[1]'', ''NVARCHAR(10)''), 
            product.value(''(@version)[1]'', ''NVARCHAR(14)''), 
            product.value(''(name[1])'', ''NVARCHAR(255)''),
            product.value(''(listId[1])'', ''NVARCHAR(9)''),
            product.value(''(listCode[1])'', ''NVARCHAR(10)'')
        FROM @InputXML.nodes(''xxx/values/value'') AS X(product)'

    EXEC(@SQL)
    
    DELETE FROM #TEMP_FILES 
    WHERE FileName = @FILENAME
END
0
Chris 15 फरवरी 2021, 18:20
2
डायनामिक स्टेटमेंट के बाहर घोषित वेरिएबल्स का इसके अंदर कोई संदर्भ नहीं है। या तो उन्हें बयान के अंदर घोषित करें (जो आपको यहां करना चाहिए), या उन्हें अपने कॉल में पैरामीटर के रूप में पास करें sys.sp_executesql (आप EXEC (@SQL) को पैरामीट्रिज नहीं कर सकते हैं, और आपको इसका उपयोग क्यों नहीं करना चाहिए )
 – 
Larnu
15 फरवरी 2021, 18:26
1
साथ ही '...\\MyServer\MyFolder\'''+ @FILENAME +'''...' इंजेक्शन के लिए खुला है। यदि आपको एक मूल्य इंजेक्ट किया गया है, तो सुनिश्चित करें कि आप मूल्यों से ठीक से बचते हैं।
 – 
Larnu
15 फरवरी 2021, 18:27
क्या मैं यह कहने में सही हूँ कि QUOTENAME(@filename, '''') को काम करना चाहिए?
 – 
Charlieface
15 फरवरी 2021, 18:28
1
संपूर्ण मान को उद्धृत करने की आवश्यकता है, @Charlieface , फ़ाइल नाम का अंतिम भाग नहीं: बल्क 'data_file'. साथ ही, ध्यान दें कि QUOTENAME का पहला पैरामीटर का डेटा प्रकार एक sysname है, इसलिए 128 वर्णों से अधिक लंबे मानों को छोटा कर देगा (जो फ़ाइल पथ हो सकते हैं)।
 – 
Larnu
15 फरवरी 2021, 18:31

1 उत्तर

सबसे बढ़िया उत्तर

आपको डायनेमिक SQL के अंदर वेरिएबल घोषित करने की आवश्यकता है (जो nvarchar होना चाहिए varchar नहीं)। फ़ाइल नाम के साथ कोई समस्या न हो यह सुनिश्चित करने के लिए आपको QUOTENAME का भी उपयोग करना चाहिए:

DECLARE @sql nvarchar(max) = N'
DECLARE @InputXML XML;
SELECT @InputXML = CAST(x AS XML) FROM OPENROWSET(BULK ' + QUOTENAME(N'\\MyServer\MyFolder\' + @FILENAME, '''') + N', SINGLE_BLOB) AS T(x)
       
INSERT INTO MyTable2 ([id],[version], [name], [listId], [listCode])
    SELECT 
    product.value(''(@id)[1]'', ''NVARCHAR(10)''), 
    product.value(''(@version)[1]'', ''NVARCHAR(14)''), 
    product.value(''(name[1])'', ''NVARCHAR(255)''),
    product.value(''(listId[1])'', ''NVARCHAR(9)''),
    product.value(''(listCode[1])'', ''NVARCHAR(10)'')
   
    FROM @InputXML.nodes(''xxx/values/value'') AS X(product)'

हालांकि, मैं कहूंगा कि मैं आपको SQL सर्वर में फ़ाइलों को लोड करने के लिए एक और तरीका खोजने का आग्रह करता हूं। डायनामिक OPENROWSET, विशेष रूप से उपयोगकर्ता इनपुट से, उचित नहीं है। बल्क इंसर्ट या बीसीपी एक विकल्प हो सकता है।

2
Charlieface 15 फरवरी 2021, 18:30
1
हालांकि मैं इसे questio के तहत नोट करता हूं, बस यह दोहराने के लिए कि QUOTENAME(N'\\MyServer\MyFolder\' + @FILENAME, '''') लंबे फ़ाइलपथ को छोटा कर देगा। QUOTENAME का पहला पैरामीटर एक sysname (nvarchar(128) का पर्यायवाची) है। यदि आप चाहते हैं कि मान अधिक लंबे हो सकते हैं, तो आपको REPLACE, या एक udf (जैसे कि मैं यहां)।
 – 
Larnu
15 फरवरी 2021, 18:37
इससे पहले कि मैं इसके साथ खिलवाड़ करूं, मैं ऐसा करने के लिए उचित क्लाइंट कोड का उपयोग करूंगा, जैसे कि bcp। फाइलों से निपटने के लिए टी-एसक्यूएल भयानक है
 – 
Charlieface
15 फरवरी 2021, 18:38
मुझे कम से कम 10 बड़ी एक्सएमएल फाइल डालनी चाहिए। लेकिन मुझे नहीं पता कि इसे बीसीपी के साथ कैसे किया जाए।
 – 
Chris
15 फरवरी 2021, 18:47
1
मैं उस पर असहमत नहीं हूं, @Charlieface, केवल यह इंगित कर रहा हूं कि QUOTENAME विशेष रूप से ऑब्जेक्ट नामों को उद्धृत करने के लिए डिज़ाइन किया गया है, फ़ाइल पथ नहीं, इसलिए इसका उपयोग उन मानों के लिए करना है जो 128 से अधिक लंबे हो सकते हैं पात्रों के परिणामस्वरूप छंटनी हो सकती है।
 – 
Larnu
15 फरवरी 2021, 18:57