SQL Server Grouping by week date but unable to convert server date to mm/dd/yyyy format using CAST

vaqhlq81  于 2023-08-02  发布在  其他
关注(0)|答案(3)|浏览(124)

I have the following query which gives the intended results but I am having trouble with using CAST to change the date formatting to mm/dd/yyyy .

Original code:

SELECT
  owneridname,
  DATEADD(week, DATEDIFF(week, 0, createdon), 0) [week],
  COUNT(svb_contactname) AS [Yes], 
  COUNT(*) - COUNT(svb_contactname) AS [No]
FROM incident
WHERE createdon >= DATEADD(day, -15, GETDATE())
GROUP BY
  owneridname,
  DATEADD(week, DATEDIFF(week, 0, createdon), 0)
ORDER BY
  Week DESC;

Results:

owneridnameweekYesNo
John Smith2023-06-26 00:00:00.00030
Alexis Smith2023-06-26 00:00:00.000012
Andrea Smith2023-06-26 00:00:00.000022
Ashley Smith2023-06-26 00:00:00.00004

I tried DATEADD(week, DATEDIFF(week, 0, CAST(createdon as date)), 0) [week] in the SELECT statement and separately CAST(DATEADD(week, DATEDIFF(week, 0, createdon), 0) as date) under GROUP BY but I receive error messages on both.

dldeef67

dldeef671#

Try this:

  • This query does not attempt to format date/time as text: doing-so in SQL is an anti-pattern.

  • The formatting of dates, numbers, etc, is a presentation-layer concern.

  • Instead, this query preserves the numeric values needed to group by week: the year-number and the week-number: you can reconstitute the first-date-of-weeek in a later CTE step.

  • Using text values for GROUP BY will always because it means there'll be string allocations, copies, and more going-on inside the DB engine - not to mention being just plain wrong for date values: using MM/dd/yyyy is particularly egregious because you cannot meaningfully lexicographically sort MM/dd/yyyy dates anyway.

  • Additionally, this query puts the GROUP BY aggregation step into a separate named CTE ( aggregatedByOwnerId ), which also means you can inspect pastFortnightIncidents independently - and re-use those CTE steps separately.

  • But my main reason for putting the GROUP BY separately is to help with the common misconception in SQL that the SELECT clause is somehow evaluated beforeGROUP BY (fun-fact: it isn't).

  • A common tarpit in SQL is trying to do too much in the SELECT clause, especially with GROUP BY .

Anyway...

SET DATEFIRST 7 -- I'm assuming you're using Sunday as first-day-of-week.

DECLARE @minCreated datetime2(7) = DATEADD( day, -15, SYSUTCDATETIME() );

WITH
pastFortnightIncidents AS (

    SELECT
        i.owneridname                    AS OwnerIdName,
        i.createdon                      AS Created,
        i.svb_contactname                AS Contact
        DATEPART( year   , i.createdon ) AS CreatedYear,
        DATEPART( week   , i.createdon ) AS CreatedWeek,
        DATEPART( isoweek, i.createdon ) AS CreatedIsoWeek

    FROM
        incident AS i

    WHERE
        i.createdon >= @minCreated
),
aggregatedByOwnerId AS (
    
    SELECT
        i.OwnerIdName,
        i.CreatedYear,
        i.CreatedWeek,
        COUNT(*)                 AS Count_All,
        COUNT( svb_contactname ) AS Count_with_ContactName,
        
    FROM
        pastFortnightIncidents AS i

    GROUP BY
        i.OwnerIdName,
        i.CreatedYear,
        i.CreatedWeek
)
SELECT
    g.OwnerIdName,
    DATEADD(
        week,
        g.CreatedWeek,
        DATEFROMPARTS( g.CreatedYear, /*M:*/ 1, /*d:*/ 1, /*h:*/ 0, /*m:*/ 0, /*s:*/ 0, /*ms:*/ 0 )
    ) AS CreatedWeekStarting,
    g.Count_with_ContactName AS "Yes",
    ( g.Count_All - g.Count_with_ContactName ) AS "No"

FROM
    aggregatedByOwnerId AS g

ORDER BY
    CreatedWeekStarting,
    OwnerIdName
7jmck4yq

7jmck4yq2#

The solution I found was to wrap CAST() around the DATEADD call in both the SELECT and GROUP BY statement, which a fellow SOer advised.

SELECT
  owneridname,
  CAST(DATEADD(week, DATEDIFF(week, 0, createdon), 0) as date) [week],
  COUNT(svb_contactname) AS [Yes],
  COUNT(*) - COUNT(svb_contactname) AS [No] 
FROM incident
WHERE createdon >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1) 
GROUP BY
  owneridname,
  CAST(DATEADD(week, DATEDIFF(week, 0, createdon), 0) as date)
ORDER BY
  Week DESC;
imzjd6km

imzjd6km3#

Format function may help you,

FORMAT([datecolumn],'dd/MM/YYYY')

Updated query,

SELECT
  owneridname,
  FORMAT(DATEADD(week, DATEDIFF(week, 0, createdon), 0),'dd/MM/yyyy') AS [week],
  COUNT(svb_contactname) AS [Yes], 
  COUNT(*) - COUNT(svb_contactname) AS [No]
FROM incident
WHERE createdon >= DATEADD(day, -15, GETDATE())
GROUP BY
  owneridname,
  DATEADD(week, DATEDIFF(week, 0, createdon), 0)
ORDER BY
  Week DESC;

相关问题