উইন-লস-টাই ডেটা থেকে স্ট্রাইক কাউন্ট এবং স্ট্রাইক টাইপ পান


15

যদি কারও জন্য বিষয়গুলি সহজ করে তোলে তবে আমি এই প্রশ্নের জন্য একটি এসকিউএল ফিডাল তৈরি করেছি ।

আমার কাছে বিভিন্ন ধরণের কল্পনাপ্রসূত স্পোর্টস ডাটাবেস রয়েছে এবং আমি কীটি বের করার চেষ্টা করছি তা হল কীভাবে "বর্তমান স্ট্রাইক" ডেটা নিয়ে আসবেন (দলটি তাদের শেষ দুটি ম্যাচআপ জিতলে 'ডাব্লু 2' এর মতো, অথবা যদি তারা হেরে যায় তবে 'এল 1') পূর্ববর্তী ম্যাচআপ জয়ের পরে তাদের শেষ ম্যাচআপ - বা 'টি 1' যদি তারা তাদের সাম্প্রতিকতম ম্যাচআপটি বেঁধে রাখে)।

এখানে আমার বুনিয়াদি স্কিমা:

CREATE TABLE FantasyTeams (
  team_id BIGINT NOT NULL
)

CREATE TABLE FantasyMatches(
    match_id BIGINT NOT NULL,
    home_fantasy_team_id BIGINT NOT NULL,
    away_fantasy_team_id BIGINT NOT NULL,
    fantasy_season_id BIGINT NOT NULL,
    fantasy_league_id BIGINT NOT NULL,
    fantasy_week_id BIGINT NOT NULL,
    winning_team_id BIGINT NULL
)

একটি মান NULLমধ্যে winning_team_idকলাম যে ম্যাচের জন্য টাই নির্দেশ করে।

এখানে 6 টি দল এবং 3 সপ্তাহের মূল্যমানের ম্যাচআপগুলির জন্য কিছু নমুনা ডেটা সহ একটি নমুনা ডিএমএল বিবৃতি রয়েছে:

INSERT INTO FantasyTeams
SELECT 1
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6

INSERT INTO FantasyMatches
SELECT 1, 2, 1, 2, 4, 44, 2
UNION
SELECT 2, 5, 4, 2, 4, 44, 5
UNION
SELECT 3, 6, 3, 2, 4, 44, 3
UNION
SELECT 4, 2, 4, 2, 4, 45, 2
UNION
SELECT 5, 3, 1, 2, 4, 45, 3
UNION
SELECT 6, 6, 5, 2, 4, 45, 6
UNION
SELECT 7, 2, 6, 2, 4, 46, 2
UNION
SELECT 8, 3, 5, 2, 4, 46, 3
UNION
SELECT 9, 4, 1, 2, 4, 46, NULL

GO

পছন্দসই আউটপুটটির একটি উদাহরণ এখানে দেওয়া হয়েছে (উপরের ডিএমএলের উপর ভিত্তি করে) যে কীভাবে প্রাপ্ত হবে তা নির্ধারণ করতে এমনকি আমার সমস্যা হচ্ছে:

| TEAM_ID | STEAK_TYPE | STREAK_COUNT |
|---------|------------|--------------|
|       1 |          T |            1 |
|       2 |          W |            3 |
|       3 |          W |            3 |
|       4 |          T |            1 |
|       5 |          L |            2 |
|       6 |          L |            1 |

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

অতিরিক্ত তথ্য: এখানে বিভিন্ন দলের সংখ্যা থাকতে পারে (and থেকে ১০ এর মধ্যে যে কোনও সংখ্যকও) এবং প্রতি ম্যাচে প্রতি দলের জন্য মোট ম্যাচআপগুলি ১ টি বৃদ্ধি পাবে। আমার কীভাবে এটি করা উচিত সে সম্পর্কে কোনও ধারণা?


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

তাহলে আপনি কি বলছেন যে আমি যে নকশাটি সেটআপ করি তা "ভাল"?
জামাউস

1
ঠিক আছে, যদি আমাকে মন্তব্যে জিজ্ঞাসা করা হয় আমি বলব: 1) এতগুলি নামে 'ফ্যান্টাসি' কেন 2) bigintএতগুলি কলামের জন্য যেখানে intসম্ভবত 3 থাকবে) কেন সমস্ত _গুলি ?! ৪) আমি টেবিলের নামগুলিকে একক হতে পছন্দ করি তবে সকলেই আমার সাথে একমত নন // তবে আপনি যা এখানে আমাদের দেখিয়েছেন
সেগুলি

উত্তর:


17

যেহেতু আপনি এসকিউএল সার্ভারে আছেন 2012 আপনি কয়েকটি নতুন উইন্ডোটিং ফাংশন ব্যবহার করতে পারেন।

with C1 as
(
  select T.team_id,
         case
           when M.winning_team_id is null then 'T'
           when M.winning_team_id = T.team_id then 'W'
           else 'L'
         end as streak_type,
         M.match_id
  from FantasyMatches as M
    cross apply (values(M.home_fantasy_team_id),
                       (M.away_fantasy_team_id)) as T(team_id)
), C2 as
(
  select C1.team_id,
         C1.streak_type,
         C1.match_id,
         lag(C1.streak_type, 1, C1.streak_type) 
           over(partition by C1.team_id 
                order by C1.match_id desc) as lag_streak_type
  from C1
), C3 as
(
  select C2.team_id,
         C2.streak_type,
         sum(case when C2.lag_streak_type = C2.streak_type then 0 else 1 end) 
           over(partition by C2.team_id 
                order by C2.match_id desc rows unbounded preceding) as streak_sum
  from C2
)
select C3.team_id,
       C3.streak_type,
       count(*) as streak_count
from C3
where C3.streak_sum = 0
group by C3.team_id,
         C3.streak_type
order by C3.team_id;

এসকিউএল ফিডল

C1হিসাব streak_typeপ্রতিটি দল এবং ম্যাচের জন্য।

C2পূর্ববর্তী streak_typeদ্বারা অর্ডার পাওয়া যায় match_id desc

C3একটি চলমান সমষ্টি উত্পন্ন streak_sumদ্বারা আদেশ match_id descএকটি পালন 0দীর্ঘ হিসেবে streak_typeগত মান সমান।

প্রধান ক্যোয়ারী যেখানে streak_sumরয়েছে তার রেখাগুলি যোগ করে 0


4
ব্যবহারের জন্য +1 LEAD()। 2012 সালে নতুন
উইন্ডোটিং

4
+1, আমি শেষ স্রোতটি পরে খুব নির্বিঘ্নে নির্ধারণ করতে LAG এ অবতরণ ক্রমটি ব্যবহার করার কৌশলটি পছন্দ করি! উপায় দ্বারা, যেহেতু ওপি শুধুমাত্র দলের ID- র চায়, আসতে পারবে না FantasyTeams JOIN FantasyMatchesসঙ্গে FantasyMatches CROSS APPLY (VALUES (home_fantasy_team_id), (away_fantasy_team_id))এবং এইভাবে সম্ভাব্য কর্ম ক্ষমতায় উন্নতি।
অ্যান্ড্রি এম

@ অ্যান্ড্রিএম ভাল ক্যাচ !! আমি উত্তর দিয়ে আপডেট করব। আপনার যদি FantasyTeamsএটি থেকে অন্য কলামগুলির প্রয়োজন হয় তবে তার পরিবর্তে মূল ক্যোয়ারিতে যোগ দেওয়া ভাল।
মিকেল এরিকসন

এই কোড উদাহরণের জন্য ধন্যবাদ - আমি এই চেষ্টা করে যাচ্ছি এবং আমি সভা থেকে বেরিয়ে আসার পরে একটু পরে রিপোর্ট করব ...>: - \
জামাসে

@ মিকায়েল এরিকসন - এটি দুর্দান্ত কাজ করে - ধন্যবাদ! তাত্ক্ষণিক প্রশ্ন - বিদ্যমান সারিগুলি আপডেট করার জন্য আমার এই ফলাফল সেটটি ব্যবহার করতে হবে (ফ্যান্টাসিটিমস.টিয়াম_আইডিতে যোগ দেওয়া) - আপনি কীভাবে এটি আপডেটের বিবৃতিতে পরিণত করার পরামর্শ দিবেন? আমি কেবল নির্বাচনকে একটি আপডেটে পরিবর্তন করার চেষ্টা শুরু করেছিলাম তবে আমি কোনও আপডেটের মাধ্যমে গ্রুপ ব্যবহার করতে পারি না। আপনি কি বলবেন যে আমি কেবল ফলাফলটি একটি টেম্প টেবিলের মধ্যে ফেলে দেওয়া উচিত এবং তার বিপরীতে যোগ হওয়া উচিত আপডেট বা অন্য কিছুতে? ধন্যবাদ!
জামস

10

এই সমস্যাটি সমাধান করার জন্য একটি স্বজ্ঞাত পদ্ধতি:

  1. প্রতিটি দলের জন্য সর্বাধিক সাম্প্রতিক ফলাফল সন্ধান করুন
  2. পূর্ববর্তী ম্যাচটি পরীক্ষা করে দেখুন এবং ফলাফলের ধরণটি মিলে গেলে স্ট্রাইক কাউন্টে একটি যুক্ত করুন
  3. দ্বিতীয় ধাপটি পুনরাবৃত্তি করুন তবে প্রথম আলাদা ফলাফলের সাথে সাথেই থামুন

এই কৌশলটি উইন্ডো ফাংশন সলিউশন (যা ডেটার পুরো স্ক্যান সম্পাদন করে) জেতে পারে, কারণ টেবিলটি বড় হতে থাকে, ধরে নিচ্ছে পুনরাবৃত্ত কৌশলটি দক্ষতার সাথে প্রয়োগ করা হয়েছে। সাফল্যের মূল চাবিকাঠি হ'ল সারিগুলি দ্রুত সন্ধান করতে দক্ষতার সূচক সরবরাহ করা (সিক্স ব্যবহার করে) এবং প্রকারগুলি এড়ানো। সূচকগুলি প্রয়োজনীয়:

-- New index #1
CREATE UNIQUE INDEX uq1 ON dbo.FantasyMatches 
    (home_fantasy_team_id, match_id) 
INCLUDE (winning_team_id);

-- New index #2
CREATE UNIQUE INDEX uq2 ON dbo.FantasyMatches 
    (away_fantasy_team_id, match_id) 
INCLUDE (winning_team_id);

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

-- Table to hold just the rows that form streaks
CREATE TABLE #StreakData
(
    team_id bigint NOT NULL,
    match_id bigint NOT NULL,
    streak_type char(1) NOT NULL,
    streak_length integer NOT NULL,
);

-- Temporary table unique clustered index
CREATE UNIQUE CLUSTERED INDEX cuq ON #StreakData (team_id, match_id);

আমার পুনরাবৃত্তির ক্যোয়ারী সমাধানটি নীচে রয়েছে ( এসকিউএল ফিডল এখানে ):

-- Solution query
WITH Streaks AS
(
    -- Anchor: most recent match for each team
    SELECT 
        FT.team_id, 
        CA.match_id, 
        CA.streak_type, 
        streak_length = 1
    FROM dbo.FantasyTeams AS FT
    CROSS APPLY
    (
        -- Most recent match
        SELECT
            T.match_id,
            T.streak_type
        FROM 
        (
            SELECT 
                FM.match_id, 
                streak_type =
                    CASE 
                        WHEN FM.winning_team_id = FM.home_fantasy_team_id
                            THEN CONVERT(char(1), 'W')
                        WHEN FM.winning_team_id IS NULL
                            THEN CONVERT(char(1), 'T')
                        ELSE CONVERT(char(1), 'L')
                    END
            FROM dbo.FantasyMatches AS FM
            WHERE 
                FT.team_id = FM.home_fantasy_team_id
            UNION ALL
            SELECT 
                FM.match_id, 
                streak_type =
                    CASE 
                        WHEN FM.winning_team_id = FM.away_fantasy_team_id
                            THEN CONVERT(char(1), 'W')
                        WHEN FM.winning_team_id IS NULL
                            THEN CONVERT(char(1), 'T')
                        ELSE CONVERT(char(1), 'L')
                    END
            FROM dbo.FantasyMatches AS FM
            WHERE
                FT.team_id = FM.away_fantasy_team_id
        ) AS T
        ORDER BY 
            T.match_id DESC
            OFFSET 0 ROWS 
            FETCH FIRST 1 ROW ONLY
    ) AS CA
    UNION ALL
    -- Recursive part: prior match with the same streak type
    SELECT 
        Streaks.team_id, 
        LastMatch.match_id, 
        Streaks.streak_type, 
        Streaks.streak_length + 1
    FROM Streaks
    CROSS APPLY
    (
        -- Most recent prior match
        SELECT 
            Numbered.match_id, 
            Numbered.winning_team_id, 
            Numbered.team_id
        FROM
        (
            -- Assign a row number
            SELECT
                PreviousMatches.match_id,
                PreviousMatches.winning_team_id,
                PreviousMatches.team_id, 
                rn = ROW_NUMBER() OVER (
                    ORDER BY PreviousMatches.match_id DESC)
            FROM
            (
                -- Prior match as home or away team
                SELECT 
                    FM.match_id, 
                    FM.winning_team_id, 
                    team_id = FM.home_fantasy_team_id
                FROM dbo.FantasyMatches AS FM
                WHERE 
                    FM.home_fantasy_team_id = Streaks.team_id
                    AND FM.match_id < Streaks.match_id
                UNION ALL
                SELECT 
                    FM.match_id, 
                    FM.winning_team_id, 
                    team_id = FM.away_fantasy_team_id
                FROM dbo.FantasyMatches AS FM
                WHERE 
                    FM.away_fantasy_team_id = Streaks.team_id
                    AND FM.match_id < Streaks.match_id
            ) AS PreviousMatches
        ) AS Numbered
        -- Most recent
        WHERE 
            Numbered.rn = 1
    ) AS LastMatch
    -- Check the streak type matches
    WHERE EXISTS
    (
        SELECT 
            Streaks.streak_type
        INTERSECT
        SELECT 
            CASE 
                WHEN LastMatch.winning_team_id IS NULL THEN 'T' 
                WHEN LastMatch.winning_team_id = LastMatch.team_id THEN 'W' 
                ELSE 'L' 
            END
    )
)
INSERT #StreakData
    (team_id, match_id, streak_type, streak_length)
SELECT
    team_id,
    match_id,
    streak_type,
    streak_length
FROM Streaks
OPTION (MAXRECURSION 0);

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

পরীক্ষার পরিকল্পনাটি কোয়েরির সাথে তুলনা করে তুলনামূলকভাবে ছোট এবং সহজ। আমি অ্যাঙ্কার অঞ্চলটি হলুদ করে দিয়েছি, এবং নীচের স্ক্রিনশটটিতে পুনরাবৃত্ত অংশটি সবুজ করেছে:

পুনরাবৃত্তির কার্যকরকরণ পরিকল্পনা

অস্থায়ী টেবিলের মধ্যে থাকা স্ট্রাইক সারিগুলির সাথে, আপনার প্রয়োজনীয় সংক্ষিপ্ত ফলাফলগুলি পাওয়া সহজ। (অস্থায়ী টেবিল ব্যবহার করে বাছাইয়ের স্পিল এড়ানো যায় যা নীচের কোয়েরিটি মূল পুনরাবৃত্ত ক্যোয়ারীর সাথে মিলিত হলে ঘটতে পারে)

-- Basic results
SELECT
    SD.team_id,
    StreakType = MAX(SD.streak_type),
    StreakLength = MAX(SD.streak_length)
FROM #StreakData AS SD
GROUP BY 
    SD.team_id
ORDER BY
    SD.team_id;

বেসিক ক্যোয়ারী কার্যকর করার পরিকল্পনা plan

FantasyTeamsটেবিলটি আপডেট করার জন্য একই প্রশ্নটি ভিত্তি হিসাবে ব্যবহার করা যেতে পারে :

-- Update team summary
WITH StreakData AS
(
    SELECT
        SD.team_id,
        StreakType = MAX(SD.streak_type),
        StreakLength = MAX(SD.streak_length)
    FROM #StreakData AS SD
    GROUP BY 
        SD.team_id
)
UPDATE FT
SET streak_type = SD.StreakType,
    streak_count = SD.StreakLength
FROM StreakData AS SD
JOIN dbo.FantasyTeams AS FT
    ON FT.team_id = SD.team_id;

বা, যদি আপনি পছন্দ করেন MERGE:

MERGE dbo.FantasyTeams AS FT
USING
(
    SELECT
        SD.team_id,
        StreakType = MAX(SD.streak_type),
        StreakLength = MAX(SD.streak_length)
    FROM #StreakData AS SD
    GROUP BY 
        SD.team_id
) AS StreakData
    ON StreakData.team_id = FT.team_id
WHEN MATCHED THEN UPDATE SET
    FT.streak_type = StreakData.StreakType,
    FT.streak_count = StreakData.StreakLength;

হয় পদ্ধতির একটি কার্যকর সম্পাদন পরিকল্পনা উত্পাদন করে (অস্থায়ী সারণীতে সারিগুলির পরিচিত সংখ্যার ভিত্তিতে):

বাস্তবায়ন পরিকল্পনা আপডেট করুন

অবশেষে, কারণ পুনরাবৃত্তির পদ্ধতিটি প্রাকৃতিকভাবে match_idএর প্রসেসিংয়ে অন্তর্ভুক্ত করে , সুতরাং match_idপ্রতিটি আউটপুটে প্রতিটি লাইন তৈরি করে এমন একটির তালিকা যুক্ত করা সহজ :

SELECT
    S.team_id,
    streak_type = MAX(S.streak_type),
    match_id_list =
        STUFF(
        (
            SELECT ',' + CONVERT(varchar(11), S2.match_id)
            FROM #StreakData AS S2
            WHERE S2.team_id = S.team_id
            ORDER BY S2.match_id DESC
            FOR XML PATH ('')
        ), 1, 1, ''),
    streak_length = MAX(S.streak_length)
FROM #StreakData AS S
GROUP BY 
    S.team_id
ORDER BY
    S.team_id;

আউটপুট:

ম্যাচের তালিকা অন্তর্ভুক্ত

হত্যা পরিকল্পনা:

ম্যাচ তালিকা কার্যকর করার পরিকল্পনা


2
চিত্তাকর্ষক! আপনার পুনরাবৃত্ত অংশের WHERE ন্যায়বিচারের EXISTS (... INTERSECT ...)পরিবর্তে ব্যবহার করার কোনও কারণ আছে কি Streaks.streak_type = CASE ...? আমি জানি পূর্ববর্তী পদ্ধতিটি কার্যকর হতে পারে যখন আপনি উভয় পক্ষের পাশাপাশি মূল্যবোধের সাথে NUL গুলি মেলাতে হবে তবে এটি ঠিক নয় যে ডান অংশটি এই ক্ষেত্রে কোনও NUL তৈরি করতে পারে, তাই ...
অ্যান্ড্রি এম

2
@ অ্যান্ড্রিএম হ্যাঁ আছে। কোডটি খুব সাবধানে বিভিন্ন জায়গায় এবং কোনও প্রকার ছাড়াই একটি পরিকল্পনা তৈরির পদ্ধতিতে লিখিত is কখন CASEব্যবহার করা হয়, অপ্টিমাইজারটি মার্জ কনটেনটেশন (যা ইউনিয়ন কী অর্ডার সংরক্ষণ করে) ব্যবহার করতে অক্ষম এবং পরিবর্তে একটি কনক্যাটেনশন প্লাস প্রকারগুলি ব্যবহার করে।
পল হোয়াইট 9

8

ফলাফল পাওয়ার আরেকটি উপায় হ'ল পুনরাবৃত্ত সিটিই

WITH TeamRes As (
SELECT FT.Team_ID
     , FM.match_id
     , Previous_Match = LAG(match_id, 1, 0) 
                        OVER (PARTITION BY FT.Team_ID ORDER BY FM.match_id)
     , Matches = Row_Number() 
                 OVER (PARTITION BY FT.Team_ID ORDER BY FM.match_id Desc)
     , Result = Case Coalesce(winning_team_id, -1)
                     When -1 Then 'T'
                     When FT.Team_ID Then 'W'
                     Else 'L'
                End 
FROM   FantasyMatches FM
       INNER JOIN FantasyTeams FT ON FT.Team_ID IN 
         (FM.home_fantasy_team_id, FM.away_fantasy_team_id)
), Streaks AS (
SELECT Team_ID, Result, 1 As Streak, Previous_Match
FROM   TeamRes
WHERE  Matches = 1
UNION ALL
SELECT tr.Team_ID, tr.Result, Streak + 1, tr.Previous_Match
FROM   TeamRes tr
       INNER JOIN Streaks s ON tr.Team_ID = s.Team_ID 
                           AND tr.Match_id = s.Previous_Match 
                           AND tr.Result = s.Result
)
Select Team_ID, Result, Max(Streak) Streak
From   Streaks
Group By Team_ID, Result
Order By Team_ID

এসকিউএলফিডাল ডেমো


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