sql >> データベース >  >> RDS >> Sqlserver

SQLサーバーでこの出力をクエリする方法

    良い一日、

    以下のソリューションがすべてのニーズを解決するかどうかを確認してください。私はあなたのデータといくつかの行でそれをテストしましたが、常に再チェックするのが最善です。一見すると、要求された結果が返されるように見えます。後で説明を追加します

    私が使用しているクエリは次のとおりです:

    DECLARE @Date DATE = '2018-06-12';
    with MyCTE as (
        SELECT 
            t.CustName,t.Country,t.RecordedTime,t.CurrNo, D = CONVERT(DATE, RecordedTime)
            ,RN_D = ROW_NUMBER() 
                OVER (partition by t.CustName order by t.CurrNo desc)
            ,RN = ROW_NUMBER() 
                OVER (partition by t.CustName order by t.CurrNo)
            ,RN_Old = ROW_NUMBER() 
                OVER (partition by t.CustName, (CASE WHEN CONVERT(DATE, RecordedTime) < @Date then 0 else 1 END) order by t.CurrNo desc)
            ,Cnt = COUNT(*) 
                OVER (partition by t.CustName)
            ,CntToday = COUNT(CASE WHEN CONVERT(DATE, RecordedTime) = @Date THEN 1 ELSE NULL END) 
                OVER (partition by t.CustName)
        FROM Test t
        where 
            -- returns rows untill current date
            CONVERT (DATE, RecordedTime) <= @Date 
            -- only if relevnat to current date
            and EXISTS (
                SELECT * FROM test t0 
                where CONVERT (DATE, RecordedTime) = @Date and t0.CustName = t.CustName
            )
    )
    ,MyCTE2 as (
        select
            CustName, Country, RecordedTime, D, CurrNo, RN_D, RN, Cnt, t2.c, History, CntToday, RN_Old
        from MyCTE t1
        left JOIN (select * from (values(1, 'NEW'),(1, 'BEFORE')) t2(c, History) ) t2 
            on t1.CurrNo = t2.c
                and CntToday > 1
                and D = @Date
        where 
            RN_D = 1 
            or (RN = 1 and D = @Date) 
            or (RN_Old = 1 and D < @Date)
    )
    ,MyCTE3 as (
        select CustName, Country, RecordedTime
            -- unmarke the bellow comment in order to get the accessories columns I used
            -- This is recommended to understand the line-of-thinking
            --, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
            , History = CASE
                WHEN CurrNo = 1 and Cnt = 1 then 'NEW'
                WHEN RN_D = 1 then 'CURRENT'
                else ISNULL(History,'BEFORE')
            END
        from MyCTE2
    )
    select CustName, Country, RecordedTime--, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
        ,Audit = CASE when History='New' then 'ADD' else 'CHANGE'  END
        , History
    from MyCTE3
    

    テストを簡単にするために、クエリ全体をテーブル関数に挿入します

    DROP FUNCTION IF EXISTS dbo.F
    GO
    CREATE FUNCTION dbo.F(@Date DATE)
    RETURNS TABLE AS RETURN (
    
    --DECLARE @Date DATE = '2018-06-12';
    with MyCTE as (
        SELECT 
            t.CustName,t.Country,t.RecordedTime,t.CurrNo, D = CONVERT(DATE, RecordedTime)
            ,RN_D = ROW_NUMBER() 
                OVER (partition by t.CustName order by t.CurrNo desc)
            ,RN = ROW_NUMBER() 
                OVER (partition by t.CustName order by t.CurrNo)
            ,RN_Old = ROW_NUMBER() 
                OVER (partition by t.CustName, (CASE WHEN CONVERT(DATE, RecordedTime) < @Date then 0 else 1 END) order by t.CurrNo desc)
            ,Cnt = COUNT(*) 
                OVER (partition by t.CustName)
            ,CntToday = COUNT(CASE WHEN CONVERT(DATE, RecordedTime) = @Date THEN 1 ELSE NULL END) 
                OVER (partition by t.CustName)
        FROM Test t
        where 
            -- returns rows untill current date
            CONVERT (DATE, RecordedTime) <= @Date 
            -- only if relevnat to current date
            and EXISTS (
                SELECT * FROM test t0 
                where CONVERT (DATE, RecordedTime) = @Date and t0.CustName = t.CustName
            )
    )
    ,MyCTE2 as (
        select
            CustName, Country, RecordedTime, D, CurrNo, RN_D, RN, Cnt, t2.c, History, CntToday, RN_Old
        from MyCTE t1
        left JOIN (select * from (values(1, 'NEW'),(1, 'BEFORE')) t2(c, History) ) t2 
            on t1.CurrNo = t2.c
                and CntToday > 1
                and D = @Date
        where 
            RN_D = 1 
            or (RN = 1 and D = @Date) 
            or (RN_Old = 1 and D < @Date)
    )
    ,MyCTE3 as (
        select CustName, Country, RecordedTime
            -- unmarke the bellow comment in order to get the accessories columns I used
            -- This is recommended to understand the line-of-thinking
            --, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
            , History = CASE
                WHEN CurrNo = 1 and Cnt = 1 then 'NEW'
                WHEN RN_D = 1 then 'CURRENT'
                else ISNULL(History,'BEFORE')
            END
        from MyCTE2
    )
    select CustName, Country, RecordedTime--, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
        ,Audit = CASE when History='New' then 'ADD' else 'CHANGE'  END
        , History
    from MyCTE3
    --order by CustName, RecordedTime
    )
    GO
    

    この関数を使用すると、複数のテストを簡単に行うことができますが、本番環境では、直接クエリを使用することをお勧めします

    -- Test
    select * from F('2018-06-01') order by CustName , RecordedTime
    select * from F('2018-06-02') order by CustName , RecordedTime
    select * from F('2018-06-03') order by CustName , RecordedTime
    select * from F('2018-06-10') order by CustName , RecordedTime
    select * from F('2018-06-11') order by CustName , RecordedTime
    select * from F('2018-06-12') order by CustName , RecordedTime
    select * from F('2018-06-13') order by CustName , RecordedTime
    select * from F('2018-06-14') order by CustName , RecordedTime
    

    /****************2018-08-1914:05イスラエル時間に更新****************/

    スレッドに参加するために、さらにいくつかの情報を追加することが重要であることに気付きました。これがお役に立てば幸いです

    まず、3つのクエリの実行プランに従ってリソース使用の割合を比較しましょう:(1)私のソリューション、(2)最初のソリューションを更新した後のmaulik kansara秒のソリューション、(3)maulikkansaraの最初のソリューション

    それでは、maulik kansara秒ソリューションのEPの画像を確認しましょう:

    このクエリはテーブルを11回スキャンします!



    1. PostgreSQLの行ごとに1回だけ遅延トリガーを実行します

    2. PHPでAmazonRDSに接続する

    3. Bea WeblogicWorkFolderはどこにありますか

    4. Javaプログラムのraise_application_errorからの文字列を表示します