पूरे डेटाबेस में GETDATE () का उपयोग बदलना


27

मुझे अज़ूर SQL डेटाबेस के लिए ऑन-प्रिमाइसेस SQL ​​सर्वर 2017 डेटाबेस को माइग्रेट करने की आवश्यकता है, और मुझे कुछ चुनौतियों का सामना करना पड़ रहा है क्योंकि वहाँ से गुजरने के लिए काफी सीमाएँ हैं।

विशेष रूप से, चूंकि एक Azure SQL डेटाबेस केवल UTC समय (नो टाइम ज़ोन) में काम करता है और हमें स्थानीय समय की आवश्यकता होती है, हमें डेटाबेस में GETDATE() हर जगह के उपयोग को बदलना होगा , जो कि मुझे अनुमान से अधिक काम साबित हुआ है।

मैंने अपने समय क्षेत्र के लिए सही ढंग से काम करने वाले स्थानीय समय को प्राप्त करने के लिए एक उपयोगकर्ता परिभाषित फ़ंक्शन बनाया:

CREATE FUNCTION [dbo].[getlocaldate]()
RETURNS datetime
AS
BEGIN
    DECLARE @D datetimeoffset;
    SET @D = CONVERT(datetimeoffset, SYSDATETIMEOFFSET()) AT TIME ZONE 'Pacific SA Standard Time';
    RETURN(CONVERT(datetime,@D));
END

जिस समस्या से मुझे परेशानी हो रही है, वह वास्तव GETDATE()में इस कार्य के साथ हर दृश्य, संग्रहीत कार्यविधि, संगणित कॉलम, डिफ़ॉल्ट मान, अन्य अवरोधों, आदि में परिवर्तन है ।

इस बदलाव को लागू करने का सबसे अच्छा तरीका क्या होगा?

हम प्रबंधित उदाहरणों के सार्वजनिक पूर्वावलोकन में हैं । यह अभी भी के साथ एक ही मुद्दा है GETDATE(), तो यह इस समस्या के साथ मदद नहीं करता है। Azure में जाना एक आवश्यकता है। इस समय क्षेत्र में इस डेटाबेस का उपयोग किया जाता है (और इसका उपयोग किया जाएगा)।

जवाबों:


17
  1. डेटाबेस ऑब्जेक्ट्स को परिभाषा के लिए SQL फ़ाइल में निर्यात करने के लिए SQL सर्वर टूल का उपयोग करें जिसमें शामिल होना चाहिए: टेबल, व्यू, ट्रिगर, एसपी, फ़ंक्शंस, इत्यादि।

  2. किसी भी टेक्स्ट एडिटर का उपयोग करके एसक्यूएल फ़ाइल (पहले बैकअप बना लें) को संपादित करें जो आपको टेक्स्ट खोजने "GETDATE()"और उसके साथ बदलने की अनुमति देता है"[dbo].[getlocaldate]()"

  3. अपने डेटाबेस ऑब्जेक्ट बनाने के लिए Azure SQL में संपादित SQL फ़ाइल चलाएँ ...

  4. डेटा का माइग्रेशन निष्पादित करें।

यहां आपके पास azure प्रलेखन से संदर्भ है: SQL Azure के लिए स्क्रिप्ट बनाना


हालांकि व्यवहार में यह दृष्टिकोण जितना लगता है उससे अधिक जटिल है, यह शायद सही और सबसे अच्छा जवाब है। मुझे इस समय के कई अंकों के समान कार्य करने हैं और मैंने उपलब्ध हर दृष्टिकोण की कोशिश की है और मुझे कुछ भी बेहतर नहीं मिला है (या वास्तव में करीब भी है)। दूसरे दृष्टिकोण पहले बहुत अच्छे लगते हैं , लेकिन वे जल्दी ही ओवरसाइट्स और गोचैम्स के बुरे सपने की तरह बन जाते हैं।
RBarryYoung

15

इस बदलाव को लागू करने का सबसे अच्छा तरीका क्या होगा?

मैं दूसरे तरीके से काम करूंगा। डेटाबेस में अपने सभी टाइमस्टैम्प को यूटीसी में परिवर्तित करें, और बस यूटीसी का उपयोग करें और प्रवाह के साथ जाएं। यदि आपको अलग-अलग tz में टाइमस्टैम्प की आवश्यकता है, तो आप एक AT TIME ZONEनिर्दिष्ट कॉलम का उपयोग करके बना सकते हैं (जैसा कि आपने ऊपर किया था) जो उस निर्दिष्ट टीबी (ऐप के लिए) में समय टिकट प्रदान करता है। लेकिन, मैं गंभीरता से विचार करूंगा कि केवल UTC ऐप में वापस आ गया है, और उस तर्क को लिख रहा है - ऐप में डिस्प्ले लॉजिक।


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

5
आपके पास क्या गारंटी होगी कि कोई भी "एप्लिकेशन और सॉफ़्टवेयर" गेटडेट () का उपयोग न करें? यानी ऐप्स में sql कोड एम्बेडेड है। यदि आप इस बात की गारंटी नहीं दे सकते हैं कि डेटाबेस को एक अलग फ़ंक्शन का उपयोग करने के लिए रिफैक्ट करने से सिर्फ असंगतता पैदा होगी।
मिस्टर मागू

@MisterMagoo यह दुकान पर प्रथाओं पर निर्भर करता है, काफी स्पष्ट रूप से मुझे लगता है कि यह एक बहुत ही मामूली चिंता है, और मैं इसे समस्या के आसपास काम करने के लिए सवाल पूछने के लिए उतना समय लेने के लिए नहीं देख सकता हूं, वास्तव में मुझे ठीक करने के लिए। यह दिलचस्प होगा यदि यह प्रश्न एज़्योर नहीं था , क्योंकि मैं इसे हैक कर सकता हूं और आपको अधिक प्रतिक्रिया दे सकता हूं। हालांकि क्लाउड स्टफ बेकार है: वे इसका समर्थन नहीं करते हैं, इसलिए आपको अपनी तरफ से कुछ बदलना होगा। मैं अपने उत्तर में दिए गए मार्ग पर जाना पसंद करूंगा और इसे सही करने में समय बिताऊंगा। इसके अलावा, आपके पास कोई गारंटी नहीं है कि जब आप Azure में जाते हैं, तो हमेशा काम करेंगे।
इवान कैरोल

@EvanCarroll, क्षमा करें, मैंने अभी अपनी टिप्पणी फिर से पढ़ी और मैंने अपना इरादा अच्छी तरह से व्यक्त नहीं किया! मेरा मतलब है कि आपके उत्तर का समर्थन (अपवित) किया गया है और इस बात को उठाया गया है कि डेटाबेस में गेटलेट () से गेटलॉक्लेट () के उपयोग को बदलने के सुझाव उन्हें ऐप की ओर से विसंगतियों के लिए खुला छोड़ देंगे, और इसके अलावा सिर्फ एक है एक बड़ी समस्या पर चिपके हुए प्लास्टर। 100% आपके उत्तर से सहमत हैं, मूल समस्या को ठीक करना सही तरीका है।
मिस्टर मागू

@MisterMagoo मैं आपकी चिंता को समझते हैं, लेकिन इस मामले में, मैं सिर्फ संग्रहित प्रक्रियाओं के माध्यम से है कि क्षुधा और सॉफ्टवेयर डेटाबेस के साथ सहभागिता गारंटी ले सकते हैं
Lamak

6

निर्यात के बजाय, मैन्युअल रूप से संपादित करें, और फिर से चलाएँ, आप डेटाबेस में सीधे काम कर सकते हैं जैसे कुछ:

DECLARE C CURSOR FOR
        SELECT sm.definition, so.type
        FROM   sys.objects so
        JOIN   sys.all_sql_modules sm ON sm.object_id = so.object_id
        WHERE  so.type IN ('P', 'V')
        ORDER BY so.name
DECLARE @SQL NVARCHAR(MAX), @ojtype NVARCHAR(MAX)
OPEN C
FETCH NEXT FROM C INTO @SQL, @ojtype
WHILE @@FETCH_STATUS = 0 BEGIN
    IF @objtype = 'P' SET @SQL = REPLACE(@SQL, 'CREATE PROCEDURE', 'ALTER PROCEDURE') 
    IF @objtype = 'V' SET @SQL = REPLACE(@SQL, 'CREATE VIEW'     , 'ALTER VIEW'     ) 
    SET @SQL = REPLACE(@SQL, 'GETDATE()', '[dbo].[getlocaldate]()') 
    --PRINT @SQL
    EXEC (@SQL)
    FETCH NEXT FROM C INTO @SQL, @ojtype
END
CLOSE C
DEALLOCATE C

बेशक यह कार्य, ट्रिगर, और आगे भी से निपटने के लिए।

कुछ कैविएट हैं:

  • आपको थोड़ा उज्जवल होने CREATEऔर PROCEDURE/ और / VIEW/ के बीच अलग / अतिरिक्त श्वेत-रिक्त स्थान से निपटने की आवश्यकता हो सकती है <other>। इसके बजाय REPLACEआप इसके बजाय जगह छोड़ने CREATEऔर DROPपहले निष्पादित करने के लिए पसंद कर सकते हैं , लेकिन यह जोखिम छोड़ने वाले sys.dependsऔर दोस्तों को किल्टर से बाहर निकलता है ALTER, भले ही ALTERआप असफल न हों, कम से कम आपके पास मौजूदा वस्तु अभी भी है जहां आप DROP+ के साथ CREATEहो सकते हैं नहीं।

  • यदि आपके पास कोई "चतुर" गंध है, तो अपने स्वयं के स्कीमा को तदर्थ TSQL के साथ संशोधित करने की तरह गंध आती है, तो आपको यह सुनिश्चित करने की आवश्यकता होगी कि खोज और प्रतिस्थापन के लिए CREATE-> ALTERइसके साथ हस्तक्षेप न करें।

  • आप ऑपरेशन के बाद पूरे एप्लिकेशन (रों) को फिर से जांचना चाहेंगे, चाहे आप कर्सर का उपयोग करें या निर्यात + संपादित करें + चलाएं।

मैंने अतीत में इसी तरह के स्कीमा-वाइड अपडेट बनाने के लिए इस पद्धति का उपयोग किया है। यह थोड़ा हैक है, और काफी बदसूरत लगता है, लेकिन कभी-कभी यह सबसे आसान / तेज तरीका है।

चूक और अन्य बाधाओं को भी इसी तरह से संशोधित किया जा सकता है, हालांकि उन्हें केवल बदला जा सकता है और बदल दिया जा सकता है। कुछ इस तरह:

DECLARE C CURSOR FOR
        SELECT AlterDefaultSQL = 'ALTER TABLE [' +st.name+ '] DROP CONSTRAINT [' + si.name + '];'
                               + CHAR(10)
                               + 'ALTER TABLE [' +st.name+ '] ADD CONSTRAINT [' + si.name + '] DEFAULT '+REPLACE(si.definition, 'GETDATE()', '[dbo].[getlocaldate]()')+' FOR '+sc.name+';'
        FROM   sys.tables st
        JOIN   sys.default_constraints si ON si.parent_object_id = st.object_id
        JOIN   sys.columns sc ON sc.default_object_id = si.object_id
DECLARE @SQL NVARCHAR(MAX)
OPEN C
FETCH NEXT FROM C INTO @SQL
WHILE @@FETCH_STATUS = 0 BEGIN
    --PRINT @SQL
    EXEC (@SQL)
    FETCH NEXT FROM C INTO @SQL
END
CLOSE C
DEALLOCATE C

कुछ और मज़ेदार जिनके साथ आपको संघर्ष करने की आवश्यकता हो सकती है: यदि आप समय से विभाजन कर रहे हैं, तो उन भागों को भी बदलने की आवश्यकता हो सकती है। समय पर विभाजन को और अधिक दानेदार बनाने के बाद, दिन के DATETIMEहिसाब से दुर्लभ हो सकते हैं, ऐसे मुद्दे हो सकते हैं जहां विभाजन के कार्य को समय-सारणी के आधार पर पिछले या अगले दिन के रूप में समझा जा सकता है, जो आपके विभाजन को आपके सामान्य प्रश्नों से अलिखित नहीं करता है।


हाँ, caveats हैं जो यह कठिन बना देता है। इसके अलावा, यह कॉलम के डिफ़ॉल्ट मानों को ध्यान में नहीं रखता है। वैसे भी धन्यवाद
Lamak

कॉलम डिफ़ॉल्ट मान और अन्य बाधाओं को sysस्कीमा और प्रोग्रामेटिक रूप से संशोधित करने के लिए भी स्कैन किया जा सकता है।
डेविड स्पिलेट

हो सकता है कि उदाहरण के साथ CREATE OR ALTER PROCEDUREकुछ कोड-जनरेशन समस्याओं में मदद करता हो; अभी भी समस्याएँ हो सकती हैं क्योंकि संग्रहीत परिभाषा CREATE PROCEDURE(तीन रिक्त स्थान) पढ़ेगी और यह न तो और न CREATE PROCEDUREही CREATE OR ALTER PROCEDURE… ._ से मेल खाता है ।
कंस्ट्रक्टर

@TheConstructor - यही मैं "अतिरिक्त व्हाट्सएप" को रेफ़ करने की बात कर रहा था। आप इसके चारों ओर एक फ़ंक्शन लिखकर प्राप्त कर सकते हैं जो पहली बार स्कैन करता है जो CREATEकि एक टिप्पणी के अंदर नहीं है और इसे बदल देता है। मैंने अतीत में ऐसा नहीं किया है, लेकिन अभी पोस्ट करने के लिए फ़ंक्शन का कोड काम नहीं है। या यदि आप गारंटी दे सकते हैं कि आपकी किसी भी वस्तु की परिभाषा में पूर्ववर्ती टिप्पणियां नहीं हैं CREATE, तो टिप्पणी के मुद्दे को अनदेखा करें और पहले उदाहरण को खोजें और बदलें CREATE
डेविड स्पिललेट

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

5

मैं वास्तव में डेविड के जवाब को पसंद करता हूं और चीजों को करने के प्रोग्रामेटिक तरीके के लिए उत्थान करता हूं।

लेकिन आप SSMS के माध्यम से Azure में परीक्षण-चलाने के लिए इसे आज आज़मा सकते हैं:

अपने डेटाबेस पर राइट क्लिक करें -> कार्य -> ​​स्क्रिप्ट उत्पन्न करें ..

[बैक स्टोरी] हमारे पास एक जूनियर डीबीए था जिसने हमारे सभी परीक्षण वातावरणों को एसक्यूएल 2008 आर 2 में अपग्रेड किया था, जबकि हमारे उत्पादन वातावरण एसक्यूएल 2008 में थे। यह एक ऐसा बदलाव है जो मुझे आज तक परेशान करता है। उत्पादन से परीक्षण करने के लिए, परीक्षण से, हमें एसक्यूएल के भीतर स्क्रिप्ट उत्पन्न करना था, स्क्रिप्ट का उपयोग करना था, और उन्नत विकल्पों में हमने एक विशाल पाठ फ़ाइल बनाने के लिए 'टाइप टू डेटा टू स्क्रिप्ट: स्कीमा एंड डेटा' विकल्प का उपयोग किया। हम अपने परीक्षण R2 डेटाबेस को सफलतापूर्वक हमारी विरासत SQL 2008 सर्वर पर ले जाने में सक्षम थे - जहाँ एक डेटाबेस को कम संस्करण में पुनर्स्थापित करने से काम नहीं होता। हमने बड़ी फ़ाइल को इनपुट करने के लिए sqlcmd का उपयोग किया - क्योंकि फाइलें अक्सर SSMS टेक्स्ट बफर के लिए बहुत बड़ी थीं।

मैं यहाँ कह रहा हूँ कि यह विकल्प शायद आपके लिए भी काम करेगा। आपको केवल एक अतिरिक्त चरण करने की आवश्यकता होगी और उत्पन्न पाठ फ़ाइल में [dbo] .getlocaldate के साथ getdate () को बदलना और बदलना होगा। (हालांकि मैं आपके फंक्शन को माइग्रेशन से पहले डेटाबेस में डालूँगा)।

(मैं डेटाबेस को पुनर्स्थापित करने के इस बैंड-सहायता में कभी भी कुशल नहीं होना चाहता था, लेकिन थोड़ी देर के लिए यह काम करने का एक बचाव तरीका बन गया। और, इसने हर बार काम किया।)

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

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


1

मूल्य बदलने के लिए सभी खरीद और udf को गतिशील रूप से बदलें

    DECLARE @Text   NVARCHAR(max), 
        @spname NVARCHAR(max), 
        @Type   CHAR(5), 
        @Sql    NVARCHAR(max) 
DECLARE @getobject CURSOR 

SET @getobject = CURSOR 
FOR SELECT sc.text, 
           so.NAME, 
           so.type 
    FROM   sys.syscomments sc 
           INNER JOIN sysobjects so 
                   ON sc.id = so.id 
    WHERE  sc.[text] LIKE '%getdate()%' 

--and type in('P','FN') 
OPEN @getobject 

FETCH next FROM @getobject INTO @Text, @spname, @Type 

WHILE @@FETCH_STATUS = 0 
  BEGIN 
      IF ( @Type = 'P' 
            OR @Type = 'FN' ) 
        SET @Text = Replace(@Text, 'getdate', 'dbo.getlocaldate') 

      SET @Text = Replace(@Text, 'create', 'alter') 

      EXECUTE Sp_executesql 
        @Text 

      PRINT @Text 

      --,@spname,@Type 
      FETCH next FROM @getobject INTO @Text, @spname, @Type 
  END 

CLOSE @getobject 

DEALLOCATE @getobject  

 

    CREATE PROCEDURE [dbo].[Testproc1] 
AS 
    SET nocount ON; 

  BEGIN 
      DECLARE @CurDate DATETIME = Getdate() 
  END

नोटिस ने टिप्पणी की sysobjects टाइप कॉलम स्थिति। मेरी स्क्रिप्ट केवल खरीद और UDF को बदल देगी।

यह स्क्रिप्ट सब बदल देगा Default Constraintजो शामिलGetDate()

    DECLARE @TableName      VARCHAR(300), 
        @constraintName VARCHAR(300), 
        @colName        VARCHAR(300), 
        @Sql            NVARCHAR(max) 
DECLARE @getobject CURSOR 

SET @getobject = CURSOR 
FOR SELECT ds.NAME, 
           sc.NAME AS colName, 
           so.NAME AS Tablename 
    --,ds.definition 
    FROM   sys.default_constraints ds 
           INNER JOIN sys.columns sc 
                   ON ds.object_id = sc.default_object_id 
           INNER JOIN sys.objects so 
                   ON so.object_id = ds.parent_object_id 
    WHERE  definition LIKE '%getdate()%' 

OPEN @getobject 

FETCH next FROM @getobject INTO @constraintName, @colName, @TableName 

WHILE @@FETCH_STATUS = 0 
  BEGIN 
      SET @Sql = 'ALTER TABLE ' + @TableName 
                 + ' DROP CONSTRAINT ' + @constraintName + '; ' 
                 + Char(13) + Char(10) + '           ' + Char(13) + Char(10) + '' 
      SET @Sql = @Sql + ' ALTER TABLE ' + @TableName 
                 + ' ADD CONSTRAINT ' + @constraintName 
                 + '          DEFAULT dbo.GetLocaledate() FOR ' 
                 + @colName + ';' + Char(13) + Char(10) + '          ' + Char(13) 
                 + Char(10) + '' 

      PRINT @Sql 

      EXECUTE sys.Sp_executesql 
        @Sql 

      --,@spname,@Type 
      FETCH next FROM @getobject INTO @constraintName, @colName, @TableName 
  END 

CLOSE @getobject 

DEALLOCATE @getobject   

1

मैंने इवान कैरोल के उत्तर को उकेरा है, क्योंकि मुझे लगता है कि यह सबसे अच्छा समाधान है। मैं अपने सहयोगियों को यह समझाने में सक्षम नहीं हुआ कि उन्हें बहुत सी # कोड बदलनी चाहिए, इसलिए मुझे उस कोड का उपयोग करना था जो डेविड स्पिललेट ने लिखा था। मैंने UDFs, डायनेमिक SQL और स्कीमा (सभी कोड उपयोग "dbo" नहीं) के साथ कुछ समस्याओं को ठीक किया है:

DECLARE C CURSOR LOCAL STATIC FOR
        SELECT sm.definition, so.type
        FROM   sys.objects so
        JOIN   sys.all_sql_modules sm ON sm.object_id = so.object_id
        WHERE  so.type IN ('P', 'V')
        AND CHARINDEX('getdate()', sm.definition) > 0
        ORDER BY so.name

DECLARE @SQL NVARCHAR(MAX), @objtype NVARCHAR(MAX)
OPEN C
WHILE 1=1 BEGIN
    FETCH NEXT FROM C INTO @SQL, @objtype
    IF @@FETCH_STATUS <> 0 BREAK

    IF @objtype = 'P' SET @SQL = REPLACE(@SQL, 'CREATE PROCEDURE', 'ALTER PROCEDURE') 
    IF @objtype = 'P' SET @SQL = REPLACE(@SQL, 'CREATE   PROCEDURE', 'ALTER PROCEDURE') /* when you write "create or alter proc" */
    IF @objtype = 'V' SET @SQL = REPLACE(@SQL, 'CREATE VIEW'     , 'ALTER VIEW'     ) 
    IF CHARINDEX('getdate())''', @sql) > 0 BEGIN  /* when dynamic SQL is used */
        IF CHARINDEX('utl.getdate())''', @sql) = 0 SET @SQL = REPLACE(@SQL, 'GETDATE()', 'utl.getdate()') 
    end
    ELSE begin
        SET @SQL = REPLACE(@SQL, 'GETDATE()', 'CONVERT(DATETIME, CONVERT(datetimeoffset,  SYSDATETIME()) AT TIME ZONE ''Central Europe Standard Time'')') 
    end
    EXEC dbo.LongPrint @String = @sql    
    EXEC (@SQL)
END
CLOSE C
DEALLOCATE C

और इस तरह डिफ़ॉल्ट बाधाओं:

DECLARE C CURSOR LOCAL STATIC FOR
        SELECT AlterDefaultSQL = 'ALTER TABLE [' +sch.name+ '].[' +st.name+ '] DROP CONSTRAINT [' + si.name + '];'
                               + CHAR(10)
                               + 'ALTER TABLE [' +sch.name+ '].[' +st.name+ '] ADD CONSTRAINT [' + si.name + '] DEFAULT '+REPLACE(si.definition, 'GETDATE()', 'CONVERT(DATETIME, CONVERT(datetimeoffset,  SYSDATETIME()) AT TIME ZONE ''Central Europe Standard Time'')')+' FOR '+sc.name+';'
        FROM   sys.tables st
        JOIN   sys.default_constraints si ON si.parent_object_id = st.object_id
        JOIN   sys.columns sc ON sc.default_object_id = si.object_id
        INNER JOIN sys.schemas sch ON sch.schema_id = st.schema_id
        WHERE CHARINDEX('getdate()', si.definition) > 0
        ORDER BY st.name, sc.name

DECLARE @SQL NVARCHAR(MAX)
OPEN C
WHILE 1=1 BEGIN
    FETCH NEXT FROM C INTO @SQL
    IF @@FETCH_STATUS <> 0 BREAK

    EXEC dbo.LongPrint @String = @sql  
    EXEC (@SQL)
    FETCH NEXT FROM C INTO @SQL
END
CLOSE C
DEALLOCATE C


UDFs
UDF का उपयोग करने का सुझाव जो आज की तारीख और समय देता है, अच्छा लगता है, लेकिन मुझे लगता है कि UDFs के साथ अभी भी पर्याप्त प्रदर्शन समस्याएं हैं, इसलिए मैंने बहुत लंबे और बदसूरत एटी टाइम ज़ोन समाधान का उपयोग करने के लिए चुना है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.