0

We have to run every week a SQL Server query taking into accounts transactions starting from the latest Saturday at 00:01 until Saturday at 23:59 (Kuwait Time). The process takes into account thousands of rows and is there fore very heavy. I decided to do it in two steps, mostly because i could not manage to make it into a single one;)

I first have to offset the SQL Server date column of each transaction to Kuwait time.

I proceed in two steps since I use this script via PHP: I first define the latest Saturday date range (so for example, if the query is run on a Saturday it will calculate the range for the previous Saturday), and then use the variables for the second script.

Here here my first query getting the last Saturday :

SELECT
    (datetime, CASE 
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Sunday' 
                     THEN DATEADD(DAY, -1, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Monday' 
                     THEN DATEADD(DAY, -2, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Tuesday' 
                     THEN DATEADD(DAY, -3, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Wednesday' 
                     THEN DATEADD(DAY, -4, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) =  'Thursday' 
                     THEN DATEADD(DAY, -5, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) =  'Friday' 
                     THEN DATEADD(DAY, -6, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Saturday' 
                     THEN DATEADD(DAY, -0, CAST(CURRENT_TIMESTAMP AS date))
               END) at time zone 'Arab Standard Time' AS start_time,
 CONVERT(datetime, 
                     CASE 
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Sunday' THEN dateadd(day,0,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Monday' THEN dateadd(day,-1,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Tuesday' THEN dateadd(day,-2,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Wednesday' THEN dateadd(day,-3,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Thursday' THEN dateadd(day,-4,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Friday' THEN dateadd(day,-5,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Saturday' THEN dateadd(day,-6,cast(CURRENT_TIMESTAMP AS date))
                     END) at time zone 'Arab Standard Time' as end_time

then I insert the variable $start_date and $end_date coming from above query in this other query to get the final result:

SELECT
    USERID,
    DEPOSIT,
    RMwin,
CASE
    WHEN DEPOSIT > 0 
        AND RMwin <= DEPOSIT 
        AND RMwin > 0 THEN
            RMWIN * 0.3 
            WHEN RMwin > DEPOSIT 
            AND DEPOSIT > 0 THEN
                DEPOSIT *.3 
                WHEN RMwin <= 0 THEN
                0 ELSE 0 
            END AS CB,
        CASE
                
                WHEN DEPOSIT + RMwin = 0 THEN
                0 ELSE 1 
            END AS check_,
            FORMAT ( min_lt, 'dd/MM/yy HH:mm' ) AS min_lt,
            format ( min_kuw, 'dd/MM/yy HH:mm' ) AS min_kuw,
            format ( max_lt, 'dd/MM/yy HH:mm' ) AS max_lt,
            format ( max_kuw, 'dd/MM/yy HH:mm' ) AS max_kuw,
            min_id,
            max_id 
        FROM
            (
            SELECT
                UserID,
                SUM ( DEPOSIT ) AS DEPOSIT,
                SUM ( RMwin ) AS RMwin,
                MIN ( AccountTranID ) AS min_id,
                MAX ( AccountTranID ) AS max_id,
                MIN ( local_time ) AS min_lt,
                MIN ( kuwait_date ) AS min_kuw,
                MAX ( local_time ) AS max_lt,
                MAX ( kuwait_date ) AS max_kuw 
            FROM
                (
                SELECT
                    AccountTranID,
                    TranType,
                    UserID,
                    datetime,
                    datetime AT TIME ZONE 'Romance Standard Time' AS local_time,
                    datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' AS kuwait_date,
                CASE
                        TranType 
                        WHEN 'GAME_B' THEN
                        - AmountReal 
                        WHEN 'GAME_W' THEN
                        - AmountReal 
                        WHEN 'REFUND' THEN
                        - AmountReal ELSE 0 
                    END AS RMwin,
                CASE
                        
                        WHEN TranType = 'DEPOSIT' THEN
                        AmountReal ELSE 0 
                    END AS DEPOSIT 
                FROM
                    admin_all.DataFeed 
                WHERE
                    datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' >= ( convert(datetime,'".$start_date."') AT TIME ZONE 'Arab Standard Time' ) 
                    AND datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' < ( convert(datetime,'".$end_date."') AT TIME ZONE 'Arab Standard Time' ) 
                ) trans 
            GROUP BY
                UserID 
            ) ok 
    ORDER BY
    CB DESC

This query is unfortunately extremely heavy for our server resources and I am trying to find a way to streamline it to reach the same result.

Would anyone have a solution to make that possible?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
R_life_R
  • 786
  • 6
  • 26
  • Your date range calculations do not work on Saturdays as start_time is *after* end_time. Last `WHEN` may need to be -7 instead of -0? – Parfait Aug 08 '20 at 19:03

3 Answers3

1

Consider DATEPART for weekday numbers and apply arithmetic to retrieve last Saturday to last Sunday relative to current date. Below two expressions can replace the long CASE statements of first query:

DATEADD(DAY, -1*(DATEPART(DW, CURRENT_TIMESTAMP)), 
        CAST(CURRENT_TIMESTAMP AS DATE)) AS LAST_SATURDAY
    
DATEADD(DAY, -1*(DATEPART(DW, CURRENT_TIMESTAMP)-1), 
        CAST(CURRENT_TIMESTAMP AS DATE)) AS LAST_SUNDAY

From there, easily integrate to large query's WHERE clause:

...
WHERE
 datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' >= 
  ( DATEADD(DAY, -1*(DATEPART(DW, CURRENT_TIMESTAMP)), 
            CAST(CURRENT_TIMESTAMP AS DATE)) AT TIME ZONE 'Arab Standard Time' ) 
AND datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' < 
  ( DATEADD(DAY, -1*(DATEPART(DW, CURRENT_TIMESTAMP)-1), 
            CAST(CURRENT_TIMESTAMP AS DATE))AT TIME ZONE 'Arab Standard Time' )
...

PHP

And when run in PHP, consider parameterization where you can even calculate the dates in PHP (without a separate SQL query that only returns constants):

$start_date = date('Y-m-d H:i:s', strtotime("last Saturday"));
$end_date = date('Y-m-d H:i:s', strtotime("last Sunday"));

$sql = "...
        WHERE 
            datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' >= ?
        AND datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' < ?
        ..."

$params = array($start_date , $end_date);

# sqlsrv API
$stmt = sqlsrv_query($conn, $sql, $params);

# odbc API
$stmt    = odbc_prepare($conn, $sql);
$success = odbc_execute($stmt, $params);

Parfait
  • 104,375
  • 17
  • 94
  • 125
0

Your first query can be made simple like this (example with (test)output for august 2020):

declare @startdate datetime = '2020-08-01 00:00:00';
with testdates(d) as (
   select @startdate as d
   union all 
   select dateadd(day,1,d) from testdates where d<='2020-08-31')
select 
  d, 
  datepart(weekday,d),
  datename(weekday,d),
  dateadd(SECOND,1,dateadd(day,-(datepart(WEEKDAY,d)%7)-7,d)) start_time,
  dateadd(day,-(datepart(WEEKDAY,d)%7),d) end_time
from testdates;

output:

d                                                                  start_time              end_time
----------------------- ----------- ------------------------------ ----------------------- -----------------------
2020-08-01 00:00:00.000 7           Saturday                       2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-02 00:00:00.000 1           Sunday                         2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-03 00:00:00.000 2           Monday                         2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-04 00:00:00.000 3           Tuesday                        2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-05 00:00:00.000 4           Wednesday                      2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-06 00:00:00.000 5           Thursday                       2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-07 00:00:00.000 6           Friday                         2020-07-25 00:00:01.000 2020-08-01 00:00:00.000
2020-08-08 00:00:00.000 7           Saturday                       2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-09 00:00:00.000 1           Sunday                         2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-10 00:00:00.000 2           Monday                         2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-11 00:00:00.000 3           Tuesday                        2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-12 00:00:00.000 4           Wednesday                      2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-13 00:00:00.000 5           Thursday                       2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-14 00:00:00.000 6           Friday                         2020-08-01 00:00:01.000 2020-08-08 00:00:00.000
2020-08-15 00:00:00.000 7           Saturday                       2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-16 00:00:00.000 1           Sunday                         2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-17 00:00:00.000 2           Monday                         2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-18 00:00:00.000 3           Tuesday                        2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-19 00:00:00.000 4           Wednesday                      2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-20 00:00:00.000 5           Thursday                       2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-21 00:00:00.000 6           Friday                         2020-08-08 00:00:01.000 2020-08-15 00:00:00.000
2020-08-22 00:00:00.000 7           Saturday                       2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-23 00:00:00.000 1           Sunday                         2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-24 00:00:00.000 2           Monday                         2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-25 00:00:00.000 3           Tuesday                        2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-26 00:00:00.000 4           Wednesday                      2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-27 00:00:00.000 5           Thursday                       2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-28 00:00:00.000 6           Friday                         2020-08-15 00:00:01.000 2020-08-22 00:00:00.000
2020-08-29 00:00:00.000 7           Saturday                       2020-08-22 00:00:01.000 2020-08-29 00:00:00.000
2020-08-30 00:00:00.000 1           Sunday                         2020-08-22 00:00:01.000 2020-08-29 00:00:00.000
2020-08-31 00:00:00.000 2           Monday                         2020-08-22 00:00:01.000 2020-08-29 00:00:00.000
2020-09-01 00:00:00.000 3           Tuesday                        2020-08-22 00:00:01.000 2020-08-29 00:00:00.000
Luuk
  • 12,245
  • 5
  • 22
  • 33
0
With DateRange As
(SELECT
    (datetime, CASE 
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Sunday' 
                     THEN DATEADD(DAY, -1, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Monday' 
                     THEN DATEADD(DAY, -2, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Tuesday' 
                     THEN DATEADD(DAY, -3, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Wednesday' 
                     THEN DATEADD(DAY, -4, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) =  'Thursday' 
                     THEN DATEADD(DAY, -5, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) =  'Friday' 
                     THEN DATEADD(DAY, -6, CAST(CURRENT_TIMESTAMP AS date))
                  WHEN DATENAME(weekday, CAST(CURRENT_TIMESTAMP AS date)) = 'Saturday' 
                     THEN DATEADD(DAY, -0, CAST(CURRENT_TIMESTAMP AS date))
               END) at time zone 'Arab Standard Time' AS start_time,
 CONVERT(datetime, 
                     CASE 
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Sunday' THEN dateadd(day,0,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Monday' THEN dateadd(day,-1,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Tuesday' THEN dateadd(day,-2,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Wednesday' THEN dateadd(day,-3,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Thursday' THEN dateadd(day,-4,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Friday' THEN dateadd(day,-5,cast(CURRENT_TIMESTAMP AS date))
                            WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Saturday' THEN dateadd(day,-6,cast(CURRENT_TIMESTAMP AS date))
                     END) at time zone 'Arab Standard Time' as end_time)

SELECT
    USERID,
    DEPOSIT,
    RMwin,
CASE
    WHEN DEPOSIT > 0 
        AND RMwin <= DEPOSIT 
        AND RMwin > 0 THEN
            RMWIN * 0.3 
            WHEN RMwin > DEPOSIT 
            AND DEPOSIT > 0 THEN
                DEPOSIT *.3 
                WHEN RMwin <= 0 THEN
                0 ELSE 0 
            END AS CB,
        CASE
                
                WHEN DEPOSIT + RMwin = 0 THEN
                0 ELSE 1 
            END AS check_,
            FORMAT ( min_lt, 'dd/MM/yy HH:mm' ) AS min_lt,
            format ( min_kuw, 'dd/MM/yy HH:mm' ) AS min_kuw,
            format ( max_lt, 'dd/MM/yy HH:mm' ) AS max_lt,
            format ( max_kuw, 'dd/MM/yy HH:mm' ) AS max_kuw,
            min_id,
            max_id 
        FROM
            (
            SELECT
                UserID,
                SUM ( DEPOSIT ) AS DEPOSIT,
                SUM ( RMwin ) AS RMwin,
                MIN ( AccountTranID ) AS min_id,
                MAX ( AccountTranID ) AS max_id,
                MIN ( local_time ) AS min_lt,
                MIN ( kuwait_date ) AS min_kuw,
                MAX ( local_time ) AS max_lt,
                MAX ( kuwait_date ) AS max_kuw 
            FROM
                (
                SELECT
                    AccountTranID,
                    TranType,
                    UserID,
                    datetime,
                    datetime AT TIME ZONE 'Romance Standard Time' AS local_time,
                    datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' AS kuwait_date,
                CASE
                        TranType 
                        WHEN 'GAME_B' THEN
                        - AmountReal 
                        WHEN 'GAME_W' THEN
                        - AmountReal 
                        WHEN 'REFUND' THEN
                        - AmountReal ELSE 0 
                    END AS RMwin,
                CASE
                        
                        WHEN TranType = 'DEPOSIT' THEN
                        AmountReal ELSE 0 
                    END AS DEPOSIT 
                FROM
                    admin_all.DataFeed 
                WHERE
                    datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' >= ( Select start_date from DateRange) AT TIME ZONE 'Arab Standard Time' ) `enter code here`
                    AND datetime AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' < ( Select end_date from DateRange) AT TIME ZONE 'Arab Standard Time' ) 
                ) trans 
            GROUP BY