প্রতিটি গ্রুপের শীর্ষ 1 সারি পান


526

আমার কাছে একটি টেবিল রয়েছে যা আমি প্রতিটি দলের জন্য সর্বশেষতম এন্ট্রি পেতে চাই। টেবিলটি এখানে:

DocumentStatusLogs টেবিল

|ID| DocumentID | Status | DateCreated |
| 2| 1          | S1     | 7/29/2011   |
| 3| 1          | S2     | 7/30/2011   |
| 6| 1          | S1     | 8/02/2011   |
| 1| 2          | S1     | 7/28/2011   |
| 4| 2          | S2     | 7/30/2011   |
| 5| 2          | S3     | 8/01/2011   |
| 6| 3          | S1     | 8/02/2011   |

টেবিলটি গোছানো হবে এবং সাজানো ক্রম DocumentIDঅনুসারে বাছাই করা হবে DateCreated। প্রত্যেকের জন্য DocumentID, আমি সর্বশেষ স্থিতি পেতে চাই।

আমার পছন্দসই আউটপুট:

| DocumentID | Status | DateCreated |
| 1          | S1     | 8/02/2011   |
| 2          | S3     | 8/01/2011   |
| 3          | S1     | 8/02/2011   |
  • প্রতিটি গ্রুপ থেকে কেবল শীর্ষস্থানীয় পেতে কি কোনও সামগ্রিক ফাংশন রয়েছে? GetOnlyTheTopনীচে সিউডো কোড দেখুন:

    SELECT
      DocumentID,
      GetOnlyTheTop(Status),
      GetOnlyTheTop(DateCreated)
    FROM DocumentStatusLogs
    GROUP BY DocumentID
    ORDER BY DateCreated DESC
  • যদি এই ধরনের ফাংশনটি বিদ্যমান না থাকে তবে আমি যে আউটপুটটি চাই তা অর্জন করার কোনও উপায় আছে কি?

  • বা প্রথম স্থানে, এটি অস্বাভাবিক ডাটাবেসের কারণে হতে পারে? আমি ভাবছি, যেহেতু আমি যা খুঁজছি তা কেবল এক সারি তাই statusএটিও কি পিতামাতার টেবিলে থাকা উচিত?

আরও তথ্যের জন্য অনুগ্রহ করে টেবিল দেখুন:

বর্তমান Documentsসারণী

| DocumentID | Title  | Content  | DateCreated |
| 1          | TitleA | ...      | ...         |
| 2          | TitleB | ...      | ...         |
| 3          | TitleC | ...      | ...         |

পিতামাতার টেবিলটি কি এমন হওয়া উচিত যাতে আমি সহজেই এর স্থিতিটি অ্যাক্সেস করতে পারি?

| DocumentID | Title  | Content  | DateCreated | CurrentStatus |
| 1          | TitleA | ...      | ...         | s1            |
| 2          | TitleB | ...      | ...         | s3            |
| 3          | TitleC | ...      | ...         | s1            |

আপডেট আমি সবেমাত্র "প্রয়োগ" কীভাবে ব্যবহার করব তা শিখেছি যা এ জাতীয় সমস্যার সমাধান করতে সহজ করে তোলে।


2
সম্ভাব্য সমাধানগুলির আরও বিশদ আলোচনা এবং তুলনা করার জন্য আমি অনুরূপ প্রশ্নটি ডিবিএতে পড়ার পরামর্শ দিচ্ছি: প্রতি গ্রুপে এন সারি পুনরুদ্ধার করা
ভ্লাদিমির বারানভ

আমি পোস্টটির দিকে তাকিয়ে চেষ্টা করেছি। স্টোরআইডি দ্বারা গোষ্ঠী ব্যবহার করা একটি ত্রুটি তৈরি করেছে।
আল্ট্রাজ

উত্তর:


753
;WITH cte AS
(
   SELECT *,
         ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC) AS rn
   FROM DocumentStatusLogs
)
SELECT *
FROM cte
WHERE rn = 1

আপনি যদি প্রতিদিন 2 টি প্রবেশিকা প্রত্যাশা করেন, তবে এটি নির্বিচারে একটি চয়ন করবে। একটি দিনের জন্য উভয় এন্ট্রি পেতে, পরিবর্তে DENSE_RANK ব্যবহার করুন

সাধারণ করা বা না করা হিসাবে এটি আপনি যদি চান তবে তা নির্ভর করে:

  • স্থিতি 2 স্থানে বজায় রাখুন
  • স্থিতির ইতিহাস সংরক্ষণ করুন
  • ...

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


5
এবং ... কি Partition By? Withআমার কাছে এটিও নতুন :( আমি
এমএসকিউএল

6
@ডোমানোকজ: পার্টিশন অনুসারে গণনা পুনরায় সেট করুন। সুতরাং এই ক্ষেত্রে এটি ডকুমেন্টআইডি প্রতি গণনা করতে বলেছে
জিবিএন

1
এইচএম, আমি অভিনয়টি নিয়ে চিন্তিত, আমি কয়েক মিলিয়ন সারি জিজ্ঞাসা করব। নির্বাচন * FROM (নির্বাচন ...) কর্মক্ষমতা প্রভাবিত করে? এছাড়াও, ROW_NUMBERপ্রতিটি সারির জন্য কি কোনও ধরণের সাবকিউরি রয়েছে?
dpp

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

1
@ অ্যাডোমানোকজ: কেবলমাত্র ডেটক্রিটেড ডিএসসি অর্ডারের মাধ্যমে আইডি
ডিএসসি

184

আমি কীভাবে ব্যবহার করব তা শিখেছি cross apply। এই পরিস্থিতিতে এটি কীভাবে ব্যবহার করবেন তা এখানে:

 select d.DocumentID, ds.Status, ds.DateCreated 
 from Documents as d 
 cross apply 
     (select top 1 Status, DateCreated
      from DocumentStatusLogs 
      where DocumentID = d.DocumentId
      order by DateCreated desc) as ds

2
সমস্যাটি এখনও সমাধান করা না হওয়ায় এটি আসলে কোনও পার্থক্য করে না।
ডিপিপি

19
আমি প্রস্তাবিত সমস্ত সমাধানের বিপরীতে আমার সময় পরীক্ষার ফলাফলগুলি পোস্ট করেছি এবং আপনার উপরে উঠে এসেছিল। আপনাকে একটি ভোট প্রদান :-)
জন ফেয়ারব্যাঙ্কস

3
বিশাল গতির উন্নতির জন্য +1। এটি উইন্ডোটিং ফাংশন যেমন ROW_NUMBER () এর চেয়ে অনেক দ্রুত। এসকিউএল যদি ROW_NUMBER () = 1 কে কোয়েরির মতো স্বীকৃতি দেয় এবং সেগুলিকে প্রয়োগে অনুকূলিত করে তোলে তবে এটি দুর্দান্ত be দ্রষ্টব্য: আমি ফলাফলগুলির প্রয়োজন হিসাবে আমি আউটর অ্যাপ্লিকেশন ব্যবহার করেছি, যদিও সেগুলি প্রয়োগে উপস্থিত ছিল না।
তমুসজেরায়েস

8
@ টিমুসজেয়স আপনি যেভাবে এক্সপোস্টোলেট করতে পারবেন না কেবল এটি একবারে তত দ্রুত ছিল কারণ এটি সর্বদা ক্ষেত্রে হয়। এটা নির্ভর করে. যেমনটি এখানে বর্ণিত আছে sqlmag.com/database-de વિકાસment
মার্টিন স্মিথ

2
আমার মন্তব্যটি একাধিক সারি রাখার বিষয়ে, এবং প্রতি গ্রুপে এই একাধিক সারিগুলির মধ্যে কেবল একটির কামনা করছে। আপনি যখন কারও কাছে এক চান তখন যোগ দেয়। প্রয়োগগুলি হ'ল যখন আপনার অনেকের কাছে একটি থাকে তবে এক থেকে এক ব্যতীত সমস্তগুলি ফিল্টার করতে চান। পরিস্থিতি: 100 জন সদস্যের জন্য, আমাকে প্রত্যেককে তাদের সেরা ফোন নম্বর দিন (যেখানে প্রত্যেকের বেশ কয়েকটি নম্বর থাকতে পারে)। এখানেই এক্সেলস প্রয়োগ করুন। কম পড়া = কম ডিস্ক অ্যাক্সেস = আরও ভাল পারফরম্যান্স। আমার অভিজ্ঞতাটি হ'ল দুর্বলভাবে ডিজাইন করা নন-নরমালাইজড ডাটাবেসগুলির সাথে।
তমুসজেরোয়াস

53

আমি এখানে বিভিন্ন প্রস্তাবনার উপর কিছু সময় রেখেছি এবং ফলাফলগুলি সত্যই জড়িত টেবিলের আকারের উপর নির্ভর করে, তবে সর্বাধিক সামঞ্জস্যপূর্ণ সমাধানটি ক্রস প্রয়োগ ব্যবহার করে এই পরীক্ষাগুলি এসকিউএল সার্ভার ২০০৮-আর 2 এর বিরুদ্ধে চালানো হয়েছিল, একটি সারণী ব্যবহার করে 137 মিলিয়ন রেকর্ড সহ 6,500 রেকর্ড এবং অন্য একটি (অভিন্ন স্কিমা)। অনুসন্ধান করা কলামগুলি টেবিলের প্রাথমিক কীটির অংশ এবং টেবিলের প্রস্থ খুব ছোট (প্রায় 30 বাইট)। আসল এক্সিকিউশন পরিকল্পনা থেকে এসকিউএল সার্ভারের দ্বারা সময়গুলি প্রতিবেদন করা হয়।

Query                                  Time for 6500 (ms)    Time for 137M(ms)

CROSS APPLY                                    17.9                17.9
SELECT WHERE col = (SELECT MAX(COL)…)           6.6               854.4
DENSE_RANK() OVER PARTITION                     6.6               907.1

আমি মনে করি সত্যই আশ্চর্যজনক বিষয়টি ক্রসের প্রয়োগের জন্য সময়টির সাথে কতটা সামঞ্জস্যপূর্ণ ছিল তা জড়িত সারিগুলির নির্বিশেষে।


8
এটি সমস্ত ডেটা বিতরণ এবং উপলভ্য সূচকের উপর নির্ভর করে। এটি ডিবিএএস-এর বিষয়ে দীর্ঘ আলোচনা করা হয়েছিল ।
ভ্লাদিমির বারানভ

48

আমি জানি এটি একটি পুরানো থ্রেড তবে TOP 1 WITH TIESসমাধানগুলি বেশ সুন্দর এবং সমাধানগুলির মাধ্যমে কিছু পড়তে সহায়ক হতে পারে।

select top 1 with ties
   DocumentID
  ,Status
  ,DateCreated
from DocumentStatusLogs
order by row_number() over (partition by DocumentID order by DateCreated desc)

শীর্ষ দফা সম্পর্কে আরও এখানে পাওয়া যাবে


7
এটি সর্বাধিক মার্জিত সমাধান ইমো
জর্জ মেনআটিস

1
সম্মত হয়েছে - এটি এসকিউএল এবং অন্যান্য ভাষাগুলির ইমোগুলির অন্যান্য সংস্করণগুলিতে খুব সহজেই করা সবচেয়ে ভাল প্রতিরূপ
ক্রিস আম্ফলেট

27

আপনি যদি কর্মক্ষমতা সম্পর্কে চিন্তিত হন তবে আপনি এটি MAX () এর মাধ্যমেও করতে পারেন:

SELECT *
FROM DocumentStatusLogs D
WHERE DateCreated = (SELECT MAX(DateCreated) FROM DocumentStatusLogs WHERE ID = D.ID)

ROW_NUMBER () এর জন্য আপনার নির্বাচনী বিবৃতিতে সমস্ত সারি এক ধরণের প্রয়োজন, যেখানে MAX নেই। আপনার প্রশ্নের তাত্পর্যপূর্ণভাবে গতি বাড়ানো উচিত।


2
ROW_NUMBER () এর সাথে পারফরম্যান্সের সমস্যাগুলি সঠিক সূচকের সাথে মোকাবেলা করা যায় না? (আমি মনে করি এটি যে কোনও উপায়ে করা উচিত)
ক্রিস্টোফার এল

8
তারিখের সময় সহ, আপনি গ্যারান্টি দিতে পারবেন না যে দুটি এন্ট্রি একই তারিখ এবং সময় যুক্ত করা হবে না। যথার্থতা যথেষ্ট বেশি নয়।
তমুসজেরোয়েস

সরলতার জন্য +1। পছন্দ করেছেন কি সম্পর্কে? 'ডকুমেন্টস্ট্যাটাসলগ ডি থেকে আইডি = নির্বাচন করুন যেখানে আইডি = (ডকুমেন্টস স্ট্যাটাসলগ থেকে আইডি নির্বাচন করুন যেখানে ডি ডকুমেন্টআইডি = ডকুমেন্টআইড আদেশের তারিখ 1 দ্বারা নির্ধারিত ডিইএসসি সীমা 1);'
সিবারসিটিজেন 1

* ইভেন্টসচুলেটটিবিএল ডি থেকে কোথায় ডেটসপিকড = নির্বাচন করুন (শীর্ষস্থানীয় 1 মিনিট (ডেটসপিকড) থেকে ইভেন্টসচেডটিবিএল WHERE ইভেন্টআইডিএফ = ডি.এভিটিআইডিএফ এবং তারিখপিক>> রূপান্তর (তারিখ, গেটেট ()))
অরুণ প্রসাদ ই

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

26
SELECT * FROM
DocumentStatusLogs JOIN (
  SELECT DocumentID, MAX(DateCreated) DateCreated
  FROM DocumentStatusLogs
  GROUP BY DocumentID
  ) max_date USING (DocumentID, DateCreated)

কি ডাটাবেস সার্ভার? এই কোডটি তাদের সকলের সাথে কাজ করে না।

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

বিটিডাব্লু, DateCreatedডকুমেন্টস টেবিলটিতে ইতিমধ্যে যদি আপনার কলামটি থাকে তবে আপনি কেবল এটি DocumentStatusLogsব্যবহার করে যোগ দিতে পারবেন (যতক্ষণ না DateCreatedএটি অনন্য DocumentStatusLogs

সম্পাদনা করুন: এমএসএসকিউএল ইউএসিং সমর্থন করে না, তাই এটিতে পরিবর্তন করুন:

ON DocumentStatusLogs.DocumentID = max_date.DocumentID AND DocumentStatusLogs.DateCreated = max_date.DateCreated

5
ক্লুটি শিরোনামে ছিল: এমএসএসকিউএল। এসকিউএল সার্ভারের ব্যবহার নেই তবে ধারণাটি ঠিক আছে।
gbn

7
@gbn বোকা মডারেটররা সাধারণত এখানে শিরোনাম থেকে গুরুত্বপূর্ণ কীওয়ার্ড মুছে দেয়। অনুসন্ধান ফলাফল বা গুগলে সঠিক উত্তরগুলি খুঁজে পাওয়া খুব কঠিন করে তোলা।
নিক

2
জেস উল্লেখ করেছেন যেmax(DateCreated)
মুলকাইটনাট

12

এটি বিষয়টিতে খুব সহজেই পাওয়া প্রশ্নগুলির মধ্যে একটি, তাই আমি এর একটি আধুনিক উত্তর দিতে চেয়েছিলাম (আমার রেফারেন্সের জন্য এবং অন্যকে সাহায্য করার জন্য উভয়ই)। ব্যবহার করে first_valueএবং overআপনি উপরের ক্যোয়ারির সংক্ষিপ্ত কাজ করতে পারেন:

Select distinct DocumentID
  , first_value(status) over (partition by DocumentID order by DateCreated Desc) as Status
  , first_value(DateCreated) over (partition by DocumentID order by DateCreated Desc) as DateCreated
From DocumentStatusLogs

এটি SQL সার্ভার 2008 এবং তারপরে কাজ করা উচিত। একটি ধারা ব্যবহার First_valueকরার সময় এটি সম্পাদন করার উপায় হিসাবে ভাবা যেতে পারে । বাছাই তালিকায় গ্রুপিংয়ের অনুমতি দেয় সুতরাং নেস্টেড সাবকোয়ারিগুলি লেখার পরিবর্তে (বিদ্যমান উত্তরগুলির অনেকের মতো) এটি আরও পঠনযোগ্য ফ্যাশনে এটি করে। আশাকরি এটা সাহায্য করবে.Select Top 1overOver


2
এটি এসকিউএল সার্ভার ২০০৮ আর 2 তে কাজ করে না। আমার মনে হয় ২০১২ সালে প্রথম_মূল্য চালু হয়েছিল!
ufo

1
খুব দ্রুত! আমি @dpp দ্বারা প্রদত্ত ক্রস অ্যাপ্লিকেশন সমাধানটি ব্যবহার করছিলাম তবে এটি দ্রুত ওয়াওএ।
ম্যাটস্লে

11

এটি বেশ পুরানো থ্রেড, তবে আমি ভেবেছিলাম যে আমি গ্রহণযোগ্য উত্তরটি আমার পক্ষে বিশেষভাবে ভাল কাজ করে নি ঠিক তেমনই আমার দুটি সেন্ট ফেলে দেব। আমি একটি বৃহত ডেটাসেটে জিবিএন এর সমাধান চেষ্টা করেছি এবং এটি মারাত্মক ধীর হয়ে গেছে (এসকিউএল সার্ভার ২০১২ সালে ৫ মিলিয়ন প্লাস রেকর্ডের উপর> 45 সেকেন্ড)। বাস্তবায়ন পরিকল্পনার দিকে তাকালে এটা স্পষ্ট যে সমস্যাটির জন্য এটি একটি SORT অপারেশন প্রয়োজন যা জিনিসগুলি উল্লেখযোগ্যভাবে ধীর করে দেয়।

এখানে একটি বিকল্প যা আমি সত্তা কাঠামো থেকে উত্তোলন করেছি যার কোনও SORT ক্রিয়াকলাপের প্রয়োজন নেই এবং একটি নন-ক্লাস্টার্ড সূচক অনুসন্ধান করে। এটি পূর্বোক্ত রেকর্ড সেটটিতে কার্যকরকরণের সময় <2 সেকেন্ডে কমিয়ে দেয়।

SELECT 
[Limit1].[DocumentID] AS [DocumentID], 
[Limit1].[Status] AS [Status], 
[Limit1].[DateCreated] AS [DateCreated]
FROM   (SELECT DISTINCT [Extent1].[DocumentID] AS [DocumentID] FROM [dbo].[DocumentStatusLogs] AS [Extent1]) AS [Distinct1]
OUTER APPLY  (SELECT TOP (1) [Project2].[ID] AS [ID], [Project2].[DocumentID] AS [DocumentID], [Project2].[Status] AS [Status], [Project2].[DateCreated] AS [DateCreated]
    FROM (SELECT 
        [Extent2].[ID] AS [ID], 
        [Extent2].[DocumentID] AS [DocumentID], 
        [Extent2].[Status] AS [Status], 
        [Extent2].[DateCreated] AS [DateCreated]
        FROM [dbo].[DocumentStatusLogs] AS [Extent2]
        WHERE ([Distinct1].[DocumentID] = [Extent2].[DocumentID])
    )  AS [Project2]
    ORDER BY [Project2].[ID] DESC) AS [Limit1]

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


5

প্রতিটি গ্রুপ থেকে শীর্ষ 1 নির্বাচন করার জন্য আমার কোড

# ডকুমেন্টস্ট্যাটাসলগ থেকে একটি নির্বাচন করুন a 
 তারিখটি তৈরি করা হয়েছে (# ডকুমেন্টস্ট্যাটাসলোগস থেকে শীর্ষ 1 তারিখের নির্বাচন করুন খ
কোথায় 
a.documentid = b.documentid
ডেটক্রিয়েটেড ডেস্কের মাধ্যমে অর্ডার করুন
)

3

উপরে থেকে ক্লিন্টের দুর্দান্ত এবং সঠিক উত্তর যাচাই করা:

নীচের দুটি প্রশ্নের মধ্যে পারফরম্যান্স আকর্ষণীয়। 52% শীর্ষ এক হচ্ছে। এবং 48% দ্বিতীয় এক হচ্ছে। অর্ডার বাইয়ের পরিবর্তে DISTINCT ব্যবহার করে পারফরম্যান্সে 4% উন্নতি। তবে অর্ডার দ্বারা একাধিক কলাম অনুসারে বাছাই করার সুবিধা রয়েছে।

IF (OBJECT_ID('tempdb..#DocumentStatusLogs') IS NOT NULL) BEGIN DROP TABLE #DocumentStatusLogs END

CREATE TABLE #DocumentStatusLogs (
    [ID] int NOT NULL,
    [DocumentID] int NOT NULL,
    [Status] varchar(20),
    [DateCreated] datetime
)

INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (2, 1, 'S1', '7/29/2011 1:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (3, 1, 'S2', '7/30/2011 2:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (6, 1, 'S1', '8/02/2011 3:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (1, 2, 'S1', '7/28/2011 4:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (4, 2, 'S2', '7/30/2011 5:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (5, 2, 'S3', '8/01/2011 6:00:00')
INSERT INTO #DocumentStatusLogs([ID], [DocumentID], [Status], [DateCreated]) VALUES (6, 3, 'S1', '8/02/2011 7:00:00')

বিকল্প 1:

    SELECT
    [Extent1].[ID], 
    [Extent1].[DocumentID],
    [Extent1].[Status], 
    [Extent1].[DateCreated]
FROM #DocumentStatusLogs AS [Extent1]
    OUTER APPLY (
        SELECT TOP 1
            [Extent2].[ID], 
            [Extent2].[DocumentID],
            [Extent2].[Status], 
            [Extent2].[DateCreated]
        FROM #DocumentStatusLogs AS [Extent2]
        WHERE [Extent1].[DocumentID] = [Extent2].[DocumentID]
        ORDER BY [Extent2].[DateCreated] DESC, [Extent2].[ID] DESC
    ) AS [Project2]
WHERE ([Project2].[ID] IS NULL OR [Project2].[ID] = [Extent1].[ID])

বিকল্প 2:

SELECT 
    [Limit1].[DocumentID] AS [ID], 
    [Limit1].[DocumentID] AS [DocumentID], 
    [Limit1].[Status] AS [Status], 
    [Limit1].[DateCreated] AS [DateCreated]
FROM (
    SELECT DISTINCT [Extent1].[DocumentID] AS [DocumentID] FROM #DocumentStatusLogs AS [Extent1]
) AS [Distinct1]
    OUTER APPLY  (
        SELECT TOP (1) [Project2].[ID] AS [ID], [Project2].[DocumentID] AS [DocumentID], [Project2].[Status] AS [Status], [Project2].[DateCreated] AS [DateCreated]
        FROM (
            SELECT 
                [Extent2].[ID] AS [ID], 
                [Extent2].[DocumentID] AS [DocumentID], 
                [Extent2].[Status] AS [Status], 
                [Extent2].[DateCreated] AS [DateCreated]
            FROM #DocumentStatusLogs AS [Extent2]
            WHERE [Distinct1].[DocumentID] = [Extent2].[DocumentID]
        )  AS [Project2]
        ORDER BY [Project2].[ID] DESC
    ) AS [Limit1]

এম Management এর ম্যানেজমেন্ট স্টুডিও: প্রথম ব্লকটি হাইলাইট এবং চালানোর পরে বিকল্প 1 এবং বিকল্প 2 উভয়ই হাইলাইট করুন, ডান ক্লিক করুন -> [আনুমানিক নির্বাহ পরিকল্পনা প্রদর্শন করুন]। তারপরে ফলাফলটি দেখতে পুরো জিনিসটি চালান।

বিকল্প 1 ফলাফল:

ID  DocumentID  Status  DateCreated
6   1   S1  8/2/11 3:00
5   2   S3  8/1/11 6:00
6   3   S1  8/2/11 7:00

বিকল্প 2 ফলাফল:

ID  DocumentID  Status  DateCreated
6   1   S1  8/2/11 3:00
5   2   S3  8/1/11 6:00
6   3   S1  8/2/11 7:00

বিঃদ্রঃ:

আমি যখন একটি যোগদান 1-থেকে- (অনেকের মধ্যে 1) হতে চাই তখন আমি অ্যাপ্লিকেশন ব্যবহার করি।

আমি যদি যোগদানটি 1-থেকে-বহু, বা বহু-বহুতে থাকতে চাই তবে আমি একটি JOIN ব্যবহার করি।

আমি ROW_NUMBER () সহ সিটিই এড়াচ্ছি যদি না আমার উন্নত কিছু করার প্রয়োজন হয় এবং উইন্ডোং পারফরম্যান্স পেনাল্টির সাথে ঠিক থাকে না।

আমি WHERE বা ON ধারাতে উপস্থিত / IN উপকরণগুলি এড়াতে পারি, কারণ আমি এটি ভয়াবহ বাস্তবায়নের পরিকল্পনার কারণ হয়েছি experienced মাইলেজ পরিবর্তিত হয়। কার্যকর করার পরিকল্পনা এবং প্রোফাইল কর্মক্ষমতা পর্যালোচনা করুন কোথায় এবং কখন প্রয়োজন হবে!


3

এই সমাধানটি প্রতিটি পার্টিশনের জন্য শীর্ষ এন সর্বাধিক সাম্প্রতিক সারিগুলি পেতে ব্যবহার করা যেতে পারে (উদাহরণস্বরূপ, WHERE বিবৃতিতে N 1 এবং পার্টিশনটি ডক_আইডি):

SELECT doc_id, status, date_created FROM 
(
    SELECT a.*, ROW_NUMBER() OVER (PARTITION BY doc_id ORDER BY date_created DESC) AS rnk FROM doc a
)
WHERE rnk = 1;

2
SELECT o.*
FROM `DocumentStatusLogs` o                   
  LEFT JOIN `DocumentStatusLogs` b                   
  ON o.DocumentID = b.DocumentID AND o.DateCreated < b.DateCreated
 WHERE b.DocumentID is NULL ;

আপনি যদি ডেটক্রিটেড দ্বারা কেবল সাম্প্রতিক নথির আদেশটি ফিরিয়ে দিতে চান তবে এটি ডকুমেন্টআইডি দ্বারা কেবল শীর্ষ 1 টি নথি ফিরিয়ে দেবে


2

CROSS APPLYআমার সমাধানের জন্য আমি যে পদ্ধতিটি ব্যবহার করেছি, এটি আমার পক্ষে এবং আমার ক্লায়েন্টদের প্রয়োজন হিসাবে কাজ করেছিল। এবং আমি যা পড়েছি তা থেকে তাদের ডাটাবেসটি যথেষ্ট পরিমাণে বাড়তে হবে সর্বোপরি সর্বোত্তম কর্মক্ষমতা সরবরাহ করা উচিত।


1

সমস্যাগুলির তিনটি পৃথক পদ্ধতির পাশাপাশি এই প্রতিটি প্রশ্নের জন্য সূচক করার সর্বোত্তম পছন্দগুলি রয়েছে (অনুগ্রহ করে সূচীগুলি নিজেই চেষ্টা করে দেখুন এবং যৌক্তিক পাঠ, অতিবাহিত সময়, সম্পাদনের পরিকল্পনা দেখুন I আমি আমার অভিজ্ঞতা থেকে পরামর্শগুলি সরবরাহ করেছি এই নির্দিষ্ট সমস্যার জন্য নির্বাহ না করে যেমন প্রশ্নগুলি)।

পদ্ধতির 1 : ROW_NUMBER () ব্যবহার করে। যদি সারি স্টোর সূচকটি পারফরম্যান্সকে বাড়িয়ে তুলতে না সক্ষম হয় তবে আপনি একত্রিতকরণ এবং গোষ্ঠীভুক্ত জিজ্ঞাসাগুলির জন্য এবং বিভিন্ন সময়ে কলামে সর্বদা আদেশ দেওয়া টেবিলগুলির জন্য অন ক্লাস্টারড / ক্লাস্টারড কলামস্টোর সূচীটি চেষ্টা করতে পারেন, কলামস্টোর সূচকটি সাধারণত সেরা পছন্দ।

;WITH CTE AS
    (
       SELECT   *,
                RN = ROW_NUMBER() OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
       FROM     DocumentStatusLogs
    )
    SELECT  ID      
        ,DocumentID 
        ,Status     
        ,DateCreated
    FROM    CTE
    WHERE   RN = 1;

পদ্ধতির 2 : FIRST_VALUE ব্যবহার করে। যদি সারি স্টোর সূচকটি পারফরম্যান্সকে বাড়িয়ে তুলতে না সক্ষম হয় তবে আপনি একত্রিতকরণ এবং গোষ্ঠীভুক্ত জিজ্ঞাসাগুলির জন্য এবং বিভিন্ন সময়ে কলামে সর্বদা আদেশ দেওয়া টেবিলগুলির জন্য অন ক্লাস্টারড / ক্লাস্টারড কলামস্টোর সূচীটি চেষ্টা করতে পারেন, কলামস্টোর সূচকটি সাধারণত সেরা পছন্দ।

SELECT  DISTINCT
    ID      = FIRST_VALUE(ID) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
    ,DocumentID
    ,Status     = FIRST_VALUE(Status) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
    ,DateCreated    = FIRST_VALUE(DateCreated) OVER (PARTITION BY DocumentID ORDER BY DateCreated DESC)
FROM    DocumentStatusLogs;

পদ্ধতির 3 : ক্রস প্রয়োগ প্রয়োগ করুন। ডকুমেন্টস্ট্যাটাসলগস টেবিলটিতে সারি স্টোর ইনডেক্স তৈরি করা ক্যোয়ারীতে ব্যবহৃত কলামগুলিকে coveringেকে রাখার জন্য একটি কলাম স্টোর সূচকের প্রয়োজন ছাড়াই ক্যোয়ারীটি আবরণ করার জন্য যথেষ্ট।

SELECT  DISTINCT
    ID      = CA.ID
    ,DocumentID = D.DocumentID
    ,Status     = CA.Status 
    ,DateCreated    = CA.DateCreated
FROM    DocumentStatusLogs D
    CROSS APPLY (
            SELECT  TOP 1 I.*
            FROM    DocumentStatusLogs I
            WHERE   I.DocumentID = D.DocumentID
            ORDER   BY I.DateCreated DESC
            ) CA;

1

আমি বিশ্বাস করি এটি ঠিক এভাবে করা যেতে পারে। এর জন্য কিছু টুইট করার প্রয়োজন হতে পারে তবে আপনি গ্রুপ থেকে সর্বাধিক নির্বাচন করতে পারেন।

এই উত্তরগুলি ওভারকিল ..

SELECT
  d.DocumentID,
  MAX(d.Status),
  MAX(d1.DateCreated)
FROM DocumentStatusLogs d, DocumentStatusLogs d1
USING(DocumentID)
GROUP BY d.DocumentID
ORDER BY DateCreated DESC

0

যে পরিস্থিতিতে আপনি সারি_কাউন্ট () ব্যবহার এড়াতে চান সেখানে আপনি বাম জোড়ও ব্যবহার করতে পারেন:

select ds.DocumentID, ds.Status, ds.DateCreated 
from DocumentStatusLogs ds
left join DocumentStatusLogs filter 
    ON ds.DocumentID = filter.DocumentID
    -- Match any row that has another row that was created after it.
    AND ds.DateCreated < filter.DateCreated
-- then filter out any rows that matched 
where filter.DocumentID is null 

উদাহরণস্বরূপ স্কিমাটির জন্য, আপনি একটি "সাবকিউরিতে নয়" ব্যবহার করতে পারেন, যা সাধারণত বাম জোড়ার মতো একই আউটপুটে সংকলিত হয়:

select ds.DocumentID, ds.Status, ds.DateCreated 
from DocumentStatusLogs ds
WHERE ds.ID NOT IN (
    SELECT filter.ID 
    FROM DocumentStatusLogs filter
    WHERE ds.DocumentID = filter.DocumentID
        AND ds.DateCreated < filter.DateCreated)

দ্রষ্টব্য, টেবিলটিতে কমপক্ষে একটি একক-কলামের অনন্য কী / সীমাবদ্ধতা / সূচি না থাকলে subquery প্যাটার্নটি কাজ করবে না, এই ক্ষেত্রে প্রাথমিক কী "আইডি"।

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


0
SELECT documentid, 
       status, 
       datecreated 
FROM   documentstatuslogs dlogs 
WHERE  status = (SELECT status 
                 FROM   documentstatuslogs 
                 WHERE  documentid = dlogs.documentid 
                 ORDER  BY datecreated DESC 
                 LIMIT  1) 

0

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

SELECT [DocumentID]
    ,[tmpRez].value('/x[2]', 'varchar(20)') AS [Status]
    ,[tmpRez].value('/x[3]', 'datetime') AS [DateCreated]
FROM (
    SELECT [DocumentID]
        ,cast('<x>' + max(cast([ID] AS VARCHAR(10)) + '</x><x>' + [Status] + '</x><x>' + cast([DateCreated] AS VARCHAR(20))) + '</x>' AS XML) AS [tmpRez]
    FROM DocumentStatusLogs
    GROUP BY DocumentID
    ) AS [tmpQry]

আপনার এসকিউএল স্টেটমেন্টটি কীভাবে এটি কাজ করবে এবং ওপি'র ক্যোয়ারী সমাধান করবে তা আপনার সর্বদা বর্ণনা করা উচিত।
সুরজ কুমার

-1

এটি আমি নিয়ে আসতে পারি সবচেয়ে ভ্যানিলা টিএসকিউএল

    SELECT * FROM DocumentStatusLogs D1 JOIN
    (
      SELECT
        DocumentID,MAX(DateCreated) AS MaxDate
      FROM
        DocumentStatusLogs
      GROUP BY
        DocumentID
    ) D2
    ON
      D2.DocumentID=D1.DocumentID
    AND
      D2.MaxDate=D1.DateCreated

দুর্ভাগ্যক্রমে ম্যাক্সডেট অনন্য নয়। একই তারিখে দুটি তারিখ প্রবেশ করা সম্ভব। সুতরাং এর ফলে প্রতি গ্রুপে নকল হতে পারে। আপনি তবে একটি পরিচয় কলাম বা জিইউডি ব্যবহার করতে পারেন। পরিচয় কলাম আপনাকে সর্বাধিক প্রবেশ করানো হবে (ডিফল্ট পরিচয় ক্যালক ব্যবহৃত হচ্ছে, 1 ... এক্স পদক্ষেপ 1)।
TamusJRoyce

ঠিক আছে, আমি একমত, তবে লেখক সর্বশেষ প্রবেশের জন্য বলেছিলেন - যা আপনি যদি কোনও স্বয়ং-বর্ধিত পরিচয় কলাম অন্তর্ভুক্ত না করেন মানে একই সময়ে যুক্ত দুটি আইটেম সমান 'সর্বশেষ'
সমৃদ্ধ এর

সর্বশেষ রেকর্ড এক রেকর্ড হবে। তাই হ্যাঁ. আপনাকে অটো-ইনক্রিমেন্ট পরিচয় কলামটি বিবেচনা করতে হবে।
তমুসজেরোয়েস

-2

এটি এসকিউএলাইটে চেক করা হয়েছে যে আপনি গ্রুপের মাধ্যমে নিম্নলিখিত সাধারণ ক্যোয়ারীটি ব্যবহার করতে পারেন

SELECT MAX(DateCreated), *
FROM DocumentStatusLogs
GROUP BY DocumentID

এখানে ম্যাক্স প্রতিটি গ্রুপের সর্বাধিক তারিখ তৈরির সহায়তা করে ।

তবে দেখে মনে হচ্ছে যে এমওয়াইএসকিউএল * -কলামগুলি সর্বাধিক তারিখের তৈরির সাথে জড়িত নয় :(

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.