SQL सर्वर को UNPIVOT का उपयोग करते समय डेटाटाइप लंबाई समान होने की आवश्यकता क्यों है?


28

UNPIVOTफ़ंक्शन को सामान्यीकृत न करने वाले फ़ंक्शन पर लागू करते समय , SQL सर्वर को आवश्यक है कि डेटाटाइप और लंबाई समान हो। मैं समझता हूं कि डेटाटाइप समान होना चाहिए लेकिन UNPIVOT को लंबाई समान होने की आवश्यकता क्यों है?

मान लीजिए कि मेरे पास निम्न नमूना डेटा है जिसे मुझे अनप्लव करने की आवश्यकता है:

CREATE TABLE People
(
    PersonId int, 
    Firstname varchar(50), 
    Lastname varchar(25)
)

INSERT INTO People VALUES (1, 'Jim', 'Smith');
INSERT INTO People VALUES (2, 'Jane', 'Jones');
INSERT INTO People VALUES (3, 'Bob', 'Unicorn');

अगर मैं इसके समान स्तंभों Firstnameऔर Lastnameस्तंभों का प्रयास करता / करती हूं :

select PersonId, ColumnName, Value  
from People
unpivot
(
  Value 
  FOR ColumnName in (FirstName, LastName)
) unpiv;

SQL सर्वर त्रुटि उत्पन्न करता है:

Msg 8167, स्तर 16, राज्य 1, पंक्ति 6

कॉलम "लास्टनाम" का प्रकार UNPIVOT सूची में निर्दिष्ट अन्य स्तंभों के प्रकार के साथ संघर्ष करता है।

त्रुटि को हल करने के लिए, हमें पहले एक Lastnameकॉलम का उपयोग करना होगा जिसमें कॉलम की लंबाई समान हो Firstname:

select PersonId, ColumnName, Value  
from
(
  select personid, 
    firstname, 
    cast(lastname as varchar(50)) lastname
  from People
) d
unpivot
(
  Value FOR 
  ColumnName in (FirstName, LastName)
) unpiv;

SQL फिडेल को डेमो के साथ देखें

SQL सर्वर 2005 में शुरू किए जा रहे UNPIVOT से पहले, मैं / कॉलम को unpivot करने के लिए एक के SELECTसाथ प्रयोग UNION ALLकरूंगा और कॉलम को एक ही लंबाई में बदलने की आवश्यकता के बिना क्वेरी चलेगी:firstnamelastname

select personid, 'firstname' ColumnName, firstname value
from People
union all
select personid, 'LastName', LastName
from People;

SQL फिडेल को डेमो के साथ देखें ।

हम CROSS APPLYडेटाटाइप पर समान लंबाई के बिना डेटा का सफलतापूर्वक उपयोग करने में भी सक्षम हैं :

select PersonId, columnname, value
from People
cross apply
(
    select 'firstname', firstname union all
    select 'lastname', lastname
) c (columnname, value);

SQL फिडेल को डेमो के साथ देखें ।

मैंने MSDN के माध्यम से पढ़ा है, लेकिन मुझे डेटाटाइप पर लंबाई को समान करने के लिए तर्क को समझाते हुए कुछ भी नहीं मिला।

UNPIVOT का उपयोग करते समय समान लंबाई की आवश्यकता के पीछे तर्क क्या है?


4
(संभवतः असंबंधित लेकिन ...) एक पुनरावर्ती CTE के दो भागों के स्तंभ प्रकारों की तुलना करते समय समान कठोरता लागू की जाती है।
एंड्री एम

जवाबों:


25

UNPIVOT का उपयोग करते समय समान लंबाई की आवश्यकता के पीछे तर्क क्या है?

यह प्रश्न केवल उन लोगों द्वारा उत्तर देने योग्य हो सकता है जिन्होंने इसके कार्यान्वयन पर काम किया था UNPIVOT। आप समर्थन के लिए उनसे संपर्क करके इसे प्राप्त करने में सक्षम हो सकते हैं । निम्नलिखित तर्क की मेरी समझ है, जो 100% सटीक नहीं हो सकती है:


T-SQL में अजीब शब्दार्थ और अन्य प्रति-सहज व्यवहार के उदाहरणों की संख्या है। इनमें से कुछ अंततः चक्रवात चक्र के हिस्से के रूप में चले जाएंगे, लेकिन अन्य कभी भी 'सुधरे' या 'निश्चित' नहीं हो सकते हैं। कुछ और से अलग, ऐसे अनुप्रयोग मौजूद हैं जो इन व्यवहारों पर निर्भर करते हैं, इसलिए पिछड़ी संगतता को संरक्षित करना होगा।

उपरोक्त उल्लिखित अजीबता के महत्वपूर्ण अनुपात के लिए निहितार्थ रूपांतरण और अभिव्यक्ति प्रकार व्युत्पत्ति खाते के नियम। मैं उन परीक्षकों से ईर्ष्या नहीं करता जिन्हें यह सुनिश्चित करना है कि SETनए संस्करणों के लिए अजीब (और अक्सर अनिर्दिष्ट) व्यवहार संरक्षित हैं ( सत्र मूल्यों के सभी संयोजनों के तहत और इसी तरह)।

कहा कि, नई भाषा सुविधाओं (स्पष्ट रूप से कोई पिछड़े अनुकूलता सामान के साथ) का परिचय देते समय, सुधार करने और अतीत की गलतियों से बचने का कोई अच्छा कारण नहीं है। नए फीचर्स जैसे कि रिकर्सिव कॉमन टेबल एक्सप्रेशंस (जैसा कि एंड्री एम द्वारा एक टिप्पणी में बताया गया है ) और UNPIVOTअपेक्षाकृत सेंस शब्दार्थ और स्पष्ट रूप से परिभाषित नियम के लिए स्वतंत्र थे।

विचारों की एक सीमा होगी कि क्या प्रकार में लंबाई सहित स्पष्ट टाइपिंग बहुत दूर है, लेकिन व्यक्तिगत रूप से मैं इसका स्वागत करता हूं। मेरे विचार में, प्रकार varchar(25)और समान नहींvarchar(50) हैं , किसी भी और से अधिक हैं और हैं। विशेष आवरण स्ट्रिंग प्रकार रूपांतरण अनावश्यक रूप से चीजों को उलझा देता है और मेरी राय में कोई वास्तविक मूल्य नहीं जोड़ता है।decimal(8)decimal(10)

कोई यह तर्क दे सकता है कि डेटा को खोने वाले केवल निहित रूपांतरणों को स्पष्ट रूप से कहा जाना चाहिए, लेकिन वहाँ भी किनारे-मामले हैं। अंततः, एक रूपांतरण की आवश्यकता होने वाली है, इसलिए हम इसे स्पष्ट कर सकते हैं।

से अंतर्निहित रूपांतरण हैं varchar(25)करने के लिए varchar(50)अनुमति दी गई थी, यह सिर्फ एक और (सबसे अधिक संभावना छिपी हुई) अंतर्निहित रूपांतरण, सभी सामान्य अजीब किनारे मामलों और साथ होगा SETकी स्थापना की संवेदनशीलता। कार्यान्वयन को सरल और सबसे स्पष्ट क्यों नहीं बनाया जा सकता है? (हालांकि, कुछ भी सही नहीं है, और यह शर्म की बात है कि छिपाना varchar(25)और varchar(50)एक के अंदर sql_variantअनुमति है।)

के UNPIVOTसाथ APPLYऔर फिर UNION ALLसे बचना (बेहतर) प्रकार के व्यवहार से बचा जाता है क्योंकि नियमों के लिए UNIONपिछड़ी संगतता के अधीन हैं, और पुस्तकों में ऑनलाइन दस्तावेज़ किए जाते हैं ताकि विभिन्न प्रकार की अनुमति दी जा सके, जब तक कि वे निहित रूपांतरण का उपयोग करने के लिए तुलनीय न हों (जिसके लिए डेटा के पूर्ववर्ती नियम पूर्ववर्ती नियमों का उपयोग करते हैं। उपयोग किया जाता है, और इसी तरह)।

वर्कअराउंड में डेटा प्रकारों के बारे में स्पष्ट होना और जहाँ आवश्यक हो, वहाँ स्पष्ट रूपांतरण जोड़ना शामिल है। यह मुझे प्रगति की तरह लग रहा है :)

स्पष्ट रूप से टाइप किए गए वर्कअराउंड को लिखने का एक तरीका:

SELECT
    U.PersonId,
    U.ColumnName,
    U.Value
FROM dbo.People AS P
CROSS APPLY
(
    VALUES (CONVERT(varchar(50), Lastname))
) AS CA (Lastname)
UNPIVOT
(
    Value FOR
    ColumnName IN (P.Firstname, CA.Lastname)
) AS U;

पुनरावर्ती CTE उदाहरण:

-- Fails
WITH R AS
(
    SELECT Dummy = 'A row'
    UNION ALL
    SELECT 'Another row'
    FROM R
    WHERE Dummy = 'A row'
)
SELECT Dummy
FROM R;

-- Succeeds
WITH R AS
(
    SELECT Dummy = CONVERT(varchar(11), 'A row')
    UNION ALL
    SELECT CONVERT(varchar(11), 'Another row')
    FROM R
    WHERE Dummy = 'A row'
)
SELECT Dummy
FROM R;

अंत में, ध्यान दें कि CROSS APPLYप्रश्न में उपयोग करने वाला फिर से लिखना एक जैसा नहीं है UNPIVOT, क्योंकि यह NULLविशेषताओं को अस्वीकार नहीं करता है ।


1

UNPIVOTऑपरेटर का इस्तेमाल करता INऑपरेटर। में ऑपरेटर के लिए विनिर्देशों (नीचे स्क्रीनशॉट) से संकेत मिलता है कि दोनों test_expression(इस मामले में, पर के बाएँ IN) और प्रत्येक expression(के दाईं ओर IN) एक ही डेटा प्रकार होना चाहिए। समानता की सकर्मक संपत्ति के लिए धन्यवाद, प्रत्येक अभिव्यक्ति समान डेटा प्रकार की होनी चाहिए।

यहाँ छवि विवरण दर्ज करें


ठीक है, मैं डेटाटाइप आवश्यकता को समझता हूं लेकिन सवाल यह है कि लंबाई समान क्यों होनी चाहिए।
टैरिन

मैंने यह अनदेखी की, और हाँ, IN ऑपरेटर आमतौर पर लंबाई के बारे में परवाह नहीं करता है।
dev_etter

एक विकल्प जो आपको लंबाई निर्दिष्ट करने की आवश्यकता को नजरअंदाज करने की अनुमति देता है, वह है कि प्रत्येक को SQL_Variant के रूप में डालना है: sqieldfall.com/#
2
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.