একাধিক কলাম থেকে শেষ তারিখগুলি পান


18

এটি মনে হয় এটি সহজ হওয়া উচিত। আমি কীভাবে সর্বশেষ তারিখগুলি পেতে পারি যা বিভিন্ন কলামে রয়েছে

DROP TABLE #indebtedness
CREATE TABLE #indebtedness (call_case CHAR(10), date1 DATETIME, date2 DATETIME, date3 DATETIME)
INSERT #indebtedness VALUES ('Key1', '2019-10-30', '2019-11-30', '2019-10-25')
INSERT #indebtedness VALUES ('Key2', '2019-10-20', '2019-10-30', '2019-10-15')
INSERT #indebtedness VALUES ('Key3', '2019-11-11', '2019-10-29', '2019-10-30')
INSERT #indebtedness VALUES ('Key4',     null    , '2019-10-29', '2019-10-13')

select call_case, ?? AS 'Latest Date' from #indebtedness 

আমি ফলাফলটি চাই:

call_case   Latest Date
Key1        2019-11-30 
Key2        2019-10-30 
Key3        2019-11-11 
Key4        2019-10-29 

উত্তর:


20

একটি CASEএক্সপ্রেশন ব্যবহার করুন :

SELECT
    call_case,
    CASE WHEN date1 > date2 AND date1 > date3
         THEN date1
         WHEN date2 > date3
         THEN date2
         ELSE date3 END AS [Latest Date]
FROM #indebtedness;

ডেমো

মনে রাখবেন যে কিছু ডাটাবেস যেমন মাইএসকিউএল, এসকিউএল সার্ভার এবং এসকিউএলাইট একটি স্কেলারের বৃহত্তম ফাংশন সমর্থন করে। এসকিউএল সার্ভারটি করে না, তাই আমরা একটি CASEঅভিব্যক্তিটিকে কর্মচক্র হিসাবে ব্যবহার করতে পারি ।

সম্পাদনা:

এটি প্রদর্শিত হয় যে আপনার প্রকৃত সারণীতে তিনটি তারিখের কলামের এক বা একাধিকটির NULLমান থাকতে পারে । আমরা উপরের প্রশ্নটি নিম্নরূপে গ্রহণ করতে পারি:

SELECT
    call_case,
    CASE WHEN (date1 > date2 OR date2 IS NULL) AND (date1 > date3 OR date3 IS NULL)
         THEN date1
         WHEN date2 > date3 OR date3 IS NULL
         THEN date2
         ELSE date3 END AS [Latest Date]
FROM #indebtedness;

ডেমো


এটি কাজ করছে না এটি 33 কলামে কেবল শেষ তারিখটি পাচ্ছে না ডেট 3 পাবেন
আহমেদ আলখতিব

1
@ আহমেদআলখতিব আমি যেখানে এক বা একাধিক তারিখের কলাম থাকতে পারে সেই ক্ষেত্রেও পরিচালনা করতে আমার উত্তর সম্পাদনা করেছি NULL
টিম বিগলেইসেন

3
তারপরে এখানে দেওয়া অনেক উত্তর ভেঙে যাবে এবং কাজ করবে না। সত্য, আপনি যদি এই চারটি কলামেও এই তুলনাটি করতে চান তবে আপনি আপনার ডাটাবেস টেবিল ডিজাইনের পুনর্বিবেচনা করতে চাইতে পারেন এবং পরিবর্তে প্রতিটি তারিখের মান পৃথক সারিতে নিয়ে যেতে পারেন । আপনার প্রয়োজনীয়তা তুচ্ছ হবে যদি আপনার প্রতিটি তারিখ পৃথক সারিতে থাকে তবে আমরা কেবল এটি MAXব্যবহার করতে পারি GROUP BY। সুতরাং আপনার প্রশ্নের আমার উত্তরটি "ঠিক করবে না", কারণ আমি মনে করি সম্ভবত আপনার ডাটাবেস ডিজাইনের পরিবর্তন হওয়া দরকার।
টিম বিজিলেইসেন

1
টিম ঠিক এই মুহূর্তে, @ আহমেদআলখতিব যদি আপনার 10 তারিখের কলাম থাকে তবে আপনার সম্ভবত ডেঙ্করমাইজড ডেটা রয়েছে। একক সারিতে একটি দম্পতি ভাল, এর অর্থ ভিন্ন জিনিস (আসুন একটি সূচনা এবং সমাপ্তি, এবং জন্মের তারিখ এবং কোনও ব্যক্তি সিস্টেমে যুক্ত হওয়ার তারিখ বলতে পারি) তবে অনেকগুলি তারিখ (তার মধ্যে 10) আপনাকে বোঝায় যে আপনি প্রতিটি কলামে যখনই কিছু পরিবর্তন হয় তখন একটি নতুন তারিখ যুক্ত করা হয়; ইতিহাস বজায় রাখতে একটি নতুন সারি সন্নিবেশ করানো হচ্ছে না। উদাহরণস্বরূপ, যদি এটি একটি বিতরণ পরিষেবা সংস্থার ডাটাবেস হয় তবে তার যাত্রার প্রতিটি সম্ভাব্য পদক্ষেপের জন্য কোনও তারিখের কলাম থাকবে না; আপনি প্রতিটি জন্য একটি নতুন সারি dোকাতে চাই।
লার্নু

1
@ আহমেদআলখতিব সেক্ষেত্রে লার্নু সঠিক - আপনার অ্যাকশন ( call_case) এবং একটি টাইমস্ট্যাম্প সহ একটি টেবিল থাকা উচিত । 50 টি কলাম সহ একক টেবিল নয়
ড্যান্ন্নো

13

বর্তমানে গৃহীত উত্তর সবচেয়ে ভালো উত্তর, কিন্তু আমি কেন ব্যাখ্যা একটি ভাল যথেষ্ট পেশা আছে মনে করি না। অন্যান্য উত্তরগুলি অবশ্যই এক নজরে অনেক পরিষ্কার দেখায় (যারা সেই কুৎসিত কেস স্টেটমেন্টটি লিখতে চায়) তবে আপনি যখন স্কেল থেকে অপারেশন শুরু করবেন তখন সম্ভবত আরও খারাপ হতে পারে।

SELECT @@VERSION

Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64) 
Mar 18 2018 09:11:49 
Copyright (c) Microsoft Corporation
Developer Edition (64-bit) on Windows 10 Enterprise 10.0 <X64> (Build 17763: )

এখানে আমি সমস্ত কিছু সেট আপ করছি

DECLARE @Offset bigint = 0;
DECLARE @Max bigint = 10000000;

DROP TABLE IF EXISTS #Indebtedness;
CREATE TABLE #Indebtedness
(
  call_case char(10) COLLATE DATABASE_DEFAULT NOT NULL,
  date1     datetime NULL,
  date2     datetime NULL,
  date3     datetime NULL
);

WHILE @Offset < @Max
BEGIN

  INSERT INTO #Indebtedness
  ( call_case, date1, date2, date3 )
    SELECT @Offset + ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL )),
           DATEADD( DAY,
                    CASE WHEN RAND() > 0 THEN 1
                         ELSE -1 END * ROUND( RAND(), 0 ),
                    CURRENT_TIMESTAMP ),
           DATEADD( DAY,
                    CASE WHEN RAND() > 0 THEN 1
                         ELSE -1 END * ROUND( RAND(), 0 ),
                    CURRENT_TIMESTAMP ),
           DATEADD( DAY,
                    CASE WHEN RAND() > 0 THEN 1
                         ELSE -1 END * ROUND( RAND(), 0 ),
                    CURRENT_TIMESTAMP )
      FROM master.dbo.spt_values a
        CROSS APPLY master.dbo.spt_values b;


  SET @Offset = @Offset + ROWCOUNT_BIG();
END;

আমার সিস্টেমে এটি আমার সারণীতে 12,872,738 সারি করে। আমি যদি উপরের প্রতিটি প্রশ্নের চেষ্টা করে দেখি (এসএসএমএসে SELECT INTOফলাফল মুদ্রণ শেষ করার জন্য এটির জন্য অপেক্ষা করার দরকার নেই), আমি নিম্নলিখিত ফলাফলগুলি পাই:

Method                                | CPU time (ms) | Elapsed time (ms) | Relative Cost
-----------------------------------------------------------------------------------------
Tim Biegeleisen (CASE)                | 13485         | 2167              | 2%
Red Devil (Subquery over MAX columns) | 55187         | 9891              | 14%
Vignesh Kumar (Subquery over columns) | 33750         | 5139              | 5%
Serkan Arslan (UNPIVOT)               | 86205         | 15023             | 12%
Metal (STRING_SPLIT)                  | 459668        | 186742            | 68%

আপনি যদি ক্যোয়ারী পরিকল্পনাগুলি সন্ধান করেন তবে এটি কেন স্পষ্টভাবে স্পষ্ট হয়ে উঠবে - যে কোনও ধরণের অপরিশোধিত বা সমষ্টি (বা স্বর্গ নিষিদ্ধ STRING_SPLIT) যুক্ত করা আপনার সমস্ত ধরণের অতিরিক্ত অপারেটরগুলির সাথে শেষ হবে যা আপনার প্রয়োজন নেই (এবং এটি পরিকল্পনাকে বাধ্য করে সমান্তরাল হয়ে যান, অন্যান্য কোয়েরিগুলি চায় এমন সংস্থানগুলি সরিয়ে নিয়ে যান)। চুক্তি অনুসারে, CASEভিত্তিক সমাধানটি সমান্তরালে যায় না, খুব দ্রুত চলে এবং অবিশ্বাস্যরকম সহজ।

এই ক্ষেত্রে, আপনার সীমাহীন সংস্থান না থাকলে (আপনি না) আপনার সহজ এবং দ্রুততম পন্থা বেছে নেওয়া উচিত।


আপনার নতুন কলাম যুক্ত করা এবং কেস স্টেটমেন্টটি প্রসারিত করা দরকার হলে কী করবেন তা একটি প্রশ্ন ছিল। হ্যাঁ, এটি অনর্থক হয়ে যায়, তবে অন্য প্রতিটি সমাধানও তা করে। যদি এটি প্রকৃতপক্ষে কোনও শ্রমসাধ্য ওয়ার্কফ্লো হয় তবে আপনার টেবিলটি নতুন করে ডিজাইন করা উচিত। আপনি যা দেখতে চান তা সম্ভবত এরকম কিছু দেখাচ্ছে:

CREATE TABLE #Indebtedness2
(
  call_case     char(10) COLLATE DATABASE_DEFAULT NOT NULL,
  activity_type bigint   NOT NULL,  -- This indicates which date# column it was, if you care
  timestamp     datetime NOT NULL
);

SELECT Indebtedness.call_case,
       Indebtedness.activity_type,
       Indebtedness.timestamp
  FROM ( SELECT call_case,
                activity_type,
                timestamp,
                ROW_NUMBER() OVER ( PARTITION BY call_case
                                    ORDER BY timestamp DESC ) RowNumber
           FROM #Indebtedness2 ) Indebtedness
  WHERE Indebtedness.RowNumber = 1;

এটি অবশ্যই সম্ভাব্য পারফরম্যান্স সমস্যা থেকে মুক্ত নয় এবং এর জন্য সতর্কতার সাথে সূচকের সুরের প্রয়োজন হবে তবে সম্ভাব্য টাইমস্ট্যাম্পগুলির একটি স্বেচ্ছাসেবী সংখ্যার পরিচালনা করার সেরা উপায় is


যদি কোনও উত্তর মুছে ফেলা হয় তবে আমি যে সংস্করণগুলি তুলনা করছি তা এখানে রয়েছে (ক্রমে)

SELECT
    call_case,
    CASE WHEN date1 > date2 AND date1 > date3
         THEN date1
         WHEN date2 > date3
         THEN date2
         ELSE date3 END AS [Latest Date]
FROM #indebtedness;

SELECT call_case,
  (SELECT Max(v) 
   FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MostRecentDate]
FROM #indebtedness

SELECT call_case,
  (SELECT
     MAX(call_case) 
   FROM ( VALUES 
            (MAX(date1)), 
            (MAX(date2))
            ,(max(date3)) 
        ) MyAlias(call_case)
  ) 
FROM #indebtedness
group by call_case

select call_case, MAX(date)  [Latest Date] from #indebtedness 
UNPIVOT(date FOR col IN ([date1], [date2], [date3])) UNPVT
GROUP BY call_case

select call_case , max(cast(x.Item as date)) as 'Latest Date' from #indebtedness  t
cross apply dbo.SplitString(concat(date1, ',', date2, ',', date3), ',') x
group by call_case

এটি দুর্দান্ত গোয়েন্দা কাজ +1 এবং আমি অবাক হয়েছি এটি কোনও উপকারকে আকর্ষণ করা এড়িয়ে গেছে।
টিম বিগলেইসেন

এটি অত্যন্ত সহায়ক উত্তর +1
আহমেদ আলখতিব

11

এটা চেষ্টা কর:

SELECT call_case,
  (SELECT
     MAX(call_case) 
   FROM ( VALUES 
            (MAX(date1)), 
            (MAX(date2))
            ,(max(date3)) 
        ) MyAlias(call_case)
  ) 
FROM #indebtedness
group by call_case

@ আহমেদআলখতিব । । এটি সেরা উত্তর। এটি NULLগুলি পরিচালনা করে , ভাল পারফরম্যান্স করা উচিত এবং সহজেই আরও কলামগুলিতে সাধারণীকরণ করা হয়।
গর্ডন লিনফ

ভ্যালু () এবং গ্রুপের ম্যাক্স () প্রয়োজন হয় না এবং কোয়েরিটিকে ধীর করে দেয়; আরও ভাল কেবল নির্বাচন করুন I.call_case, (নির্বাচন করুন MAX (d.date) থেকে FROM (VALUES ((i.date1)), ((i.date2)), ((i.date3))) AS d (তারিখ)) AS সর্বোচ্চ # তারিখ থেকে # ইন্ডিগেটনেস এআই
টমাস ফ্রাঞ্জ

8

এসকিউএল ফিডল

ব্যবহার MAX()

SELECT call_case,
  (SELECT Max(v) 
   FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MostRecentDate]
FROM #indebtedness

ব্যবহার CASE

 SELECT
        CASE
            WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
            WHEN Date2 >= Date1 AND Date2 >= Date3 THEN Date2
            WHEN Date3 >= Date1 AND Date3 >= Date2 THEN Date3
            ELSE                                        Date1
        END AS MostRecentDate
 FROM  #indebtedness

2
নিচের ভোটের বিষয়ে একটি সূত্র নয়, আমার মতে আপনার ম্যাক্স ব্যবহারের উদাহরণটি গ্রহণযোগ্য সমাধানের চেয়ে অনেক বেশি মার্জিত (যা তারিখের কলামগুলির একটি বড় সংখ্যা থাকলে খুব জটিল হয়ে উঠবে)।
বার্নিএল

1
আমি সম্মত, আরও মূল্যবোধের সাথে পদ্ধতিটি ব্যবহার করে VALUESএকটি বৃহত CASEপ্রকাশের চেয়ে অনেক বেশি স্কেলযোগ্য । আমিও কেন এটি হ্রাস পেয়েছিলাম তা শিখতে চাই, যেমন ভোটার মনে করেন যে এসকিউএল নিয়ে সমস্যা আছে এবং তাই যদি তারা আমাদের সমস্যাটি বলেন তবে আমরা সকলেই এ থেকে শিখতে পারি।
লার্নু

1

আমার দৃষ্টিতে, পিওট হ'ল এই ক্যোয়ারির জন্য সেরা এবং দক্ষ বিকল্প। এমএস এসকিউএল সার্ভারে অনুলিপি করুন এবং আটকান। নীচে লিখিত কোড চেক করুন:

CREATE TABLE #indebtedness (call_case CHAR(10), date1 DATETIME, date2 DATETIME, date3 DATETIME)
INSERT #indebtedness VALUES ('Key1', '2019-10-30', '2019-11-30', '2019-10-31')
INSERT #indebtedness VALUES ('Key2', '2019-10-20', '2019-10-30', '2019-11-21')
INSERT #indebtedness VALUES ('Key3', '2019-11-11', '2019-10-29', '2019-10-30')
INSERT #indebtedness VALUES ('Key4', Null, '2019-10-29', '2019-10-13')

--Solution-1:
SELECT        
    call_case,
    MAX(RecnetDate) as MaxDateColumn         
FROM #indebtedness
UNPIVOT
(RecnetDate FOR COL IN ([date1], [date2], [date3])) as TRANSPOSE
GROUP BY call_case 

--Solution-2:
select 
    call_case, case 
    when date1>date2 and date1 > date3 then date1
    when date2>date3                   then date2
    when date3>date1                   then date1 
   else date3 end as date
from #indebtedness as a 


Drop table #indebtedness

0

এটি অন্যদের যেমন নির্দেশ করেছে তেমন ডিজাইনের স্তরে পুনরায় মূল্যায়ন করা উচিত। নীচে আপনি দুটি ফলাফল সারণী ব্যবহার করে যা আপনার ফলাফলগুলি সন্ধান করছেন তাতে এটি আরও ভালভাবে সম্পাদনের জন্য একটি পৃথক নকশার উদাহরণ রয়েছে। এটি বৃদ্ধি অনেক বেশি অনুকূল করে তুলবে।

এখানে একটি উদাহরণ (বিভিন্ন টেবিলের নাম ব্যবহৃত):

-- Drop pre-existing tables
DROP TABLE #call_log
DROP TABLE #case_type

-- Create table for Case Types
CREATE TABLE #case_type (id INT PRIMARY KEY CLUSTERED NOT NULL, 
    descript VARCHAR(50) NOT NULL)
INSERT #case_type VALUES (1,'No Answer')
INSERT #case_type VALUES (2,'Answer')
INSERT #case_type VALUES (3,'Not Exist')
INSERT #case_type VALUES (4,'whatsapp')
INSERT #case_type VALUES (5,'autodial')
INSERT #case_type VALUES (6,'SMS')

-- Create a Call Log table with a primary identity key and also an index on the call types
CREATE TABLE #call_log (call_num BIGINT PRIMARY KEY CLUSTERED IDENTITY NOT NULL,
    call_type INT NOT NULL REFERENCES #case_type(id), call_date DATETIME)
CREATE NONCLUSTERED INDEX ix_call_log_entry_type ON #call_log(call_type)
INSERT #call_log(call_type, call_date) VALUES (1,'2019-11-30')
INSERT #call_log(call_type, call_date) VALUES (2,'2019-10-15')
INSERT #call_log(call_type, call_date) VALUES (3,null)
INSERT #call_log(call_type, call_date) VALUES (3,'2019-10-29')
INSERT #call_log(call_type, call_date) VALUES (1,'2019-10-25')
INSERT #call_log(call_type, call_date) VALUES (2,'2019-10-30')
INSERT #call_log(call_type, call_date) VALUES (3,'2019-10-13')
INSERT #call_log(call_type, call_date) VALUES (2,'2019-10-20')
INSERT #call_log(call_type, call_date) VALUES (1,'2019-10-30')

-- use an aggregate to show only the latest date for each case type
SELECT DISTINCT ct.descript, MAX(cl.call_date) AS "Date" 
    FROM #call_log cl JOIN #case_type ct ON cl.call_type = ct.id GROUP BY ct.descript

এটি আরও কেস ধরণের যুক্ত করার অনুমতি দেয়, আরও অনেক লগ এন্ট্রি যুক্ত করা যায় এবং আরও ভাল নকশা সরবরাহ করে।

শেখার উদ্দেশ্যে এটি কেবল উদাহরণ।


ব্যবহারকারীর অবস্থার উপর নির্ভর করে ডাটাবেসটিকে নতুন করে ডিজাইন করা কোনও বিকল্প হতে পারে না। অন্যান্য বিকল্প রয়েছে যা ডেটা পুনর্গঠন প্রয়োজন হয় না।
ডিডাব্লুআরল্যান্ডস

@ ডিডাব্লুআরল্যান্ডস আমি সম্মতি জানাব যে এটি কোনও বিকল্প নাও হতে পারে এবং সম্ভবত আমার এটি আরও পরিষ্কার করা উচিত ছিল। আমি কেবলমাত্র অন্যান্য মন্তব্যের ভিত্তিতে প্রতিক্রিয়া জানাচ্ছিলাম যে যদি পুনরায় ডিজাইন করা সম্ভব হয় তবে এটি আরও ভাল সমাধান এবং একটি উদাহরণ সরবরাহ করে। এবং আমি ভালভাবে জানি যে অনেকগুলি কারণ রয়েছে যে একটি ডাটাবেস পুনরায় ডিজাইন করতে সক্ষম হবে না।
হনোক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.