পার্টিশন ফাংশন COUNT () ওপরে DISTINCT ব্যবহার করে সম্ভব


90

আমি মোটামুটি স্বতন্ত্র নুম্যুজারের মোট চলমান পেতে নিম্নলিখিতগুলি লেখার চেষ্টা করছি:

NumUsers = COUNT(DISTINCT [UserAccountKey]) OVER (PARTITION BY [Mth])

ম্যানেজমেন্ট স্টুডিওগুলি এটি সম্পর্কে খুব খুশি মনে হয় না। আমি DISTINCTকীওয়ার্ডটি সরিয়ে দিলে ত্রুটিটি অদৃশ্য হয়ে যায় তবে এর পরে এটি কোনও স্বতন্ত্র গণনা হবে না।

DISTINCTপার্টিশন ফাংশনগুলির মধ্যে এটি সম্ভব বলে মনে হয় না। আমি কীভাবে পৃথক গণনাটি সন্ধান করব? আমি কি আরও traditional তিহ্যবাহী পদ্ধতি ব্যবহার করি যেমন একটি সম্পর্কযুক্ত সাবকোয়ারি?

এটি আরও খানিকটা অনুসন্ধান করে দেখলে, এই OVERফাংশনগুলি ওরাকলকে এইভাবে আলাদাভাবে কাজ করে যেগুলি SQL-Serverচলমান মোট গণনা করতে ব্যবহার করা যায় না ।

আমি এসকিউএলফিডেলে এখানে একটি জীবন্ত উদাহরণ যুক্ত করেছি যেখানে আমি একটি চলমান মোট গণনা করার জন্য একটি পার্টিশন ফাংশন ব্যবহার করার চেষ্টা করি।


4
COUNTএর ORDER BYপরিবর্তে PARTITION BY2008 সালে অশুভ সংজ্ঞায়িত করা হয়েছে I'm আমি অবাক হয়েছি এটি আপনাকে এটিকে একেবারেই দিচ্ছে। প্রতি ডকুমেন্টেশন , আপনি একটি মঞ্জুরিপ্রাপ্ত নন ORDER BYএকটি সমষ্টিগত ফাংশন জন্য।
দামিয়েন_ও_বিশ্বাসীরা

হ্যাঁ - মনে করুন আমি কিছু ওরাকল কার্যকারিতা নিয়ে বিভ্রান্ত হচ্ছি; এই চলমান মোট রান এবং চলমান গণনাগুলি আরও কিছুটা জড়িত থাকবে
কেন

উত্তর:


180

ব্যবহার করে খুব সহজ সমাধান রয়েছে dense_rank()

dense_rank() over (partition by [Mth] order by [UserAccountKey]) 
+ dense_rank() over (partition by [Mth] order by [UserAccountKey] desc) 
- 1

এটি আপনাকে যা ঠিকভাবে চেয়েছিল তা দেবে: প্রতিটি মাসের মধ্যে স্বতন্ত্র ইউজার অ্যাকাউন্ট অ্যাকাউন্টের সংখ্যা।


23
একটি বিষয় সম্পর্কে সতর্কতা অবলম্বন করতে হবে dense_rank()তা হ'ল এটি NULL গণনা করবে যেখানে COUNT(field) OVERনা। এর কারণে আমি আমার সমাধানে এটিকে কাজে লাগাতে পারি না তবে আমি এখনও মনে করি এটি বেশ চালাক।
bf2020

4
তবে আমি প্রতি বছরের মাসগুলিতে চলমান মোট পৃথক ব্যবহারকারীর গোপনীয়তার সন্ধান করছি: নিশ্চিত না যে এটি কীভাবে উত্তর দেয়?
কেন

4
@ bf2020, যদি হতে পারে NULLমান UserAccountKey, তাহলে আপনি এই শব্দটি যোগ করতে হবে: -MAX(CASE WHEN UserAccountKey IS NULL THEN 1 ELSE 0 END) OVER (PARTITION BY Mth)। আইডিয়াটি নীচে নীচে লার্সরনব্যাকের উত্তর থেকে নেওয়া হয়েছে। মূলত, যদি UserAccountKeyহয়েছে NULLমূল্যবোধ, আপনি অতিরিক্ত বিয়োগ করতে প্রয়োজন 1ফলাফল থেকে, কারণ DENSE_RANKগন্য NULLs মানের।
ভ্লাদিমির বরানভ

dense_rankউইন্ডো ফাংশন একটি ফ্রেম আছে যখন এই সমাধান ব্যবহার করার জন্য এখানে একটি আলোচনা । SQL সার্ভার না অনুমতি দেয় dense_rankএকটি উইন্ডো ফ্রেম সঙ্গে ব্যবহার: stackoverflow.com/questions/63527035/...
K4M

6

নেক্রোমেন্সিং:

DENSE_RANK এর মাধ্যমে ম্যাক্সের মাধ্যমে পার্টিশনের মাধ্যমে একটি COUNT টি DISTINCT অনুকরণ করা আপেক্ষিকভাবে সহজ:

;WITH baseTable AS
(
    SELECT 'RM1' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM1' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR2' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR2' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR3' AS ADR
    UNION ALL SELECT 'RM3' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM3' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM3' AS RM, 'ADR2' AS ADR
)
,CTE AS
(
    SELECT RM, ADR, DENSE_RANK() OVER(PARTITION BY RM ORDER BY ADR) AS dr 
    FROM baseTable
)
SELECT
     RM
    ,ADR

    ,COUNT(CTE.ADR) OVER (PARTITION BY CTE.RM ORDER BY ADR) AS cnt1 
    ,COUNT(CTE.ADR) OVER (PARTITION BY CTE.RM) AS cnt2 
    -- Not supported
    --,COUNT(DISTINCT CTE.ADR) OVER (PARTITION BY CTE.RM ORDER BY CTE.ADR) AS cntDist
    ,MAX(CTE.dr) OVER (PARTITION BY CTE.RM ORDER BY CTE.RM) AS cntDistEmu 
FROM CTE

দ্রষ্টব্য:
এটি অনুমান করা ক্ষেত্রগুলি হ'ল নন-নালার ক্ষেত্র।
ক্ষেত্রগুলিতে যদি এক বা একাধিক NULL- এন্ট্রি থাকে তবে আপনাকে 1 টি বিয়োগ করতে হবে।


5

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

-- subtract an extra 1 if null was ranked within the partition,
-- which only happens if there were rows where [Include] <> 'Y'
dense_rank() over (
  partition by [Mth] 
  order by case when [Include] = 'Y' then [UserAccountKey] else null end asc
) 
+ dense_rank() over (
  partition by [Mth] 
  order by case when [Include] = 'Y' then [UserAccountKey] else null end desc
)
- max(case when [Include] = 'Y' then 0 else 1 end) over (partition by [Mth])
- 1

একটি বর্ধিত উদাহরণ সহ একটি এসকিউএল ফিডল এখানে পাওয়া যাবে।


4
আপনার ধারণাটি যখন হতে পারে তখন কাজের [Include]সাথে মূল সূত্রটি ( আপনার উত্তর সম্পর্কে যে কথা বলছেন তার জটিলতা ছাড়াই ) তৈরি করতে ব্যবহার করা যেতে পারে । সূত্রে এই শব্দটি যোগ করুন । dense_rank()UserAccountKeyNULL-MAX(CASE WHEN UserAccountKey IS NULL THEN 1 ELSE 0 END) OVER (PARTITION BY Mth)
ভ্লাদিমির বড়ানোভ

5

আমি মনে করি এসকিউএল-সার্ভার ২০০৮ আরআর-তে এটি করার একমাত্র উপায় হ'ল একটি সম্পর্কযুক্ত সাবকোয়ারি ব্যবহার করা, বা একটি বাহ্যিক প্রয়োগ:

SELECT  datekey,
        COALESCE(RunningTotal, 0) AS RunningTotal,
        COALESCE(RunningCount, 0) AS RunningCount,
        COALESCE(RunningDistinctCount, 0) AS RunningDistinctCount
FROM    document
        OUTER APPLY
        (   SELECT  SUM(Amount) AS RunningTotal,
                    COUNT(1) AS RunningCount,
                    COUNT(DISTINCT d2.dateKey) AS RunningDistinctCount
            FROM    Document d2
            WHERE   d2.DateKey <= document.DateKey
        ) rt;

আপনার প্রস্তাবিত সিনট্যাক্সটি ব্যবহার করে এটি এসকিউএল-সার্ভার ২০১২- এ করা যেতে পারে :

SELECT  datekey,
        SUM(Amount) OVER(ORDER BY DateKey) AS RunningTotal
FROM    document

তবে, DISTINCTএখনও ব্যবহারের অনুমতি নেই, সুতরাং যদি DISTINCT প্রয়োজন হয় এবং / অথবা আপগ্রেড করা কোনও বিকল্প না হয় তবে আমি মনে করি OUTER APPLYএটি আপনার সেরা বিকল্প is


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