?
Solved

Help with SQL Query

Posted on 2013-12-16
6
Medium Priority
?
364 Views
Last Modified: 2013-12-17
I have 3 tables (TableA, TableB, TableC).  They all have a common ID column, with TableA having a 1:M relationship with TableB and TableC.

TableA: ID, DATE, TYPE
TableB: ID, TYPE
TableC: ID, TYPE

I want to write a query that outputs a table with the following columns on 168 rows (unique day of week and hour of day)

DOW: Day of Week
HOD: Hour of Day
COUNT: Count of Records in TableA for each hour of day/day of week combination
COUNTTYPEYESA: Count of Records in TableA for each hour of day/day of week combination where TYPE='YES' in TableA
COUNTTYPEYESB: Count of Records in TableA for each hour of day/day of week combination where TYPE='YES' in TableB
COUNTTYPEYESBC: Count of Records in TableA for each hour of day/day of week combination where TYPE='YES' in TableB and TableC


I have written the following query, but it seems as if the counts are for TableC.  I just want to get the count for distinct IDs (i.e. records in TableA)



SELECT
DATEPART(WEEKDAY,DATE) AS DOW,
DATEPART(HOUR,DATE) AS HOD,
COUNT(TableA.ID) AS ALLCOUNT,
COUNT(CASE TableA.TYPE='YES' THEN 1 ELSE NULL END) AS COUNTTYPEYESA,
COUNT(CASE TableB.TYPE='YES' THEN 1 ELSE NULL END) AS COUNTTYPEYESB,
SUM(CASE WHEN TableB.TYPE='YES' AND TableC.TYPE='YES') AS COUNTTYPEYESBC,

FROM TableA, TableB, TableC
WHERE TableA.ID = TableB.ID AND TableB.ID = TableC.ID

GROUP BY DATEPART(HOUR,DATE),DATEPART(WEEKDAY,DATE)
ORDER BY DOW, HOD

Open in new window

0
Comment
Question by:VAMS1
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
6 Comments
 
LVL 32

Expert Comment

by:awking00
ID: 39722485
Can you provide some sample data and the expected results so we have something to test?
0
 
LVL 34

Expert Comment

by:Brian Crowe
ID: 39722520
SELECT DATEPART(WEEKDAY, A.DATE) AS DOW,
   DATEPART(HOUR, A.DATE) AS HOD,
   COUNT(DISTINCT A.ID) AS ALLCOUNT,
   SUM(CASE WHEN AYes.ID IS NOT NULL THEN 1 ELSE 0 END) AS COUNTTYPEYESA,
   SUM(CASE WHEN BYes.ID IS NOT NULL THEN 1 ELSE 0 END) AS COUNTTYPEYESB,
   SUM(CASE WHEN CYes.ID IS NOT NULL THEN 1 ELSE 0 END) AS COUNTTYPEYESBC,
FROM TableA AS A
LEFT OUTER JOIN TableA AS AYes
   ON A.ID = AYes.ID
   AND AYes.TYPE = 'Yes'
LEFT OUTER JOIN TableB AS BYes
   INNER JOIN TableC AS CYes
      ON BYes.ID = CYes.ID
      AND CYes.TYPE = 'Yes'
   ON A.ID = BYes.ID
   AND BYes.TYPE = 'Yes'
GROUP BY DATEPART(HOUR, A.DATE), DATEPART(WEEKDAY, A.DATE)
ORDER BY DATEPART(HOUR, A.DATE), DATEPART(WEEKDAY, A.DATE)
0
 
LVL 32

Expert Comment

by:awking00
ID: 39722541
I don't think that will produce 168 rows unless the date field in tableA just happens to cover every hour for every day of the week.
0
Get proactive database performance tuning online

At Percona’s web store you can order full Percona Database Performance Audit in minutes. Find out the health of your database, and how to improve it. Pay online with a credit card. Improve your database performance now!

 
LVL 69

Expert Comment

by:Scott Pletcher
ID: 39722799
I can't tell for sure if you need the DISTINCT in the COUNTs below or not; naturally uncomment them if you do need them :-) .



--Input parameters------------------------------------------------------------------------------------------------------

-- specify first day to report on; that day and the next six will be totaled.
DECLARE @start_date datetime
SET @start_date = GETDATE() - 7


--Main code-------------------------------------------------------------------------------------------------------------
-- strip time from @start_time
SET @start_date = DATEADD(DAY, DATEDIFF(DAY, 0, @start_date), 0)

;WITH
-- gen 0-167, as overall hour numbers
cteDigits AS (
    SELECT 0 AS digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
    SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
),
cteTally AS (
    SELECT [100s].digit * 100 + [10s].digit * 10 + [1s].digit AS tally
    FROM cteDigits [1s]
    CROSS JOIN cteDigits [10s]
    INNER JOIN cteDigits [100s] ON [100s].digit BETWEEN 0 AND 1
    WHERE
        [100s].digit * 100 + [10s].digit * 10 + [1s].digit <= 167
)
SELECT
    DayOfWeek AS [Day of Week], t.tally % 24 AS [Hour of Day],
    COUNT(a.date) AS COUNT,
    COUNT(/*DISTINCT*/ CASE WHEN a.type = 'YES' THEN a.id END) AS COUNTTYPEYESA,
    COUNT(/*DISTINCT*/ CASE WHEN b.type = 'YES' THEN a.id END) AS COUNTTYPEYESB,
    COUNT(/*DISTINCT*/ CASE WHEN c.type = 'YES' THEN a.id END) AS COUNTTYPEYESBC
FROM cteTally t
CROSS APPLY (
    SELECT DATEADD(HOUR, t.tally, @start_date) AS Day_Hour
) AS ca1
CROSS APPLY (
    --produces a consistent DayOfWeek value (1=Sun,2=Mon,etc.) regardless of DATEFIRST and/or language setting.
    SELECT CASE WHEN DATEDIFF(DAY, 5, Day_Hour) % 7 = 0 THEN 7 ELSE DATEDIFF(DAY, 5, ca1.Day_Hour) % 7 END AS DayOfWeek
) AS ca2
LEFT OUTER JOIN dbo.TableA a ON
    a.date >= ca1.Day_Hour AND a.date < DATEADD(HOUR, 1, ca1.Day_Hour)
LEFT OUTER JOIN dbo.TableB b ON
    b.id = a.id AND
    b.type = 'YES'
LEFT OUTER JOIN dbo.TableC c ON
    c.id = b.id AND
    c.type = 'YES'
GROUP BY
    DayOfWeek, t.tally % 24
ORDER BY
    [Day of Week], [Hour of Day]
0
 
LVL 49

Accepted Solution

by:
PortletPaul earned 2000 total points
ID: 39722803
This should solve the 'distinctiveness'
SELECT
      DATEPART(WEEKDAY, DATE)                                                                  AS DOW
    , DATEPART(HOUR, DATE)                                                                     AS HOD
    , COUNT(DISTINCT TableA.ID)                                                                AS ALLCOUNT
    , COUNT(DISTINCT CASE WHEN TableA.TYPE = 'YES' THEN TableA.ID END)                         AS COUNTTYPEYESA
    , COUNT(DISTINCT CASE WHEN TableB.TYPE = 'YES' THEN TableA.ID END)                         AS COUNTTYPEYESB
    , COUNT(DISTINCT CASE WHEN TableB.TYPE = 'YES' AND TableC.TYPE = 'YES' THEN TableA.ID END) AS COUNTTYPEYESBC

FROM TableA
      INNER JOIN TableB
            ON TableA.ID = TableB.ID
      INNER JOIN TableC
            ON TableB.ID = TableC.ID

GROUP BY
      DATEPART(HOUR, DATE)
    , DATEPART(WEEKDAY, DATE)
ORDER BY
      DOW, HOD
;

Open in new window

but it won't guarantee 168 rows as mentioned by awking00
0
 
LVL 49

Expert Comment

by:PortletPaul
ID: 39722814
by the way:
if TableB or TableC don't have records for every TableA.id then use LEFT JOINS instead of inner joins.
0

Featured Post

Will your db performance match your db growth?

In Percona’s white paper “Performance at Scale: Keeping Your Database on Its Toes,” we take a high-level approach to what you need to think about when planning for database scalability.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A Stored Procedure in Microsoft SQL Server is a powerful feature that it can be used to execute the Data Manipulation Language (DML) or Data Definition Language (DDL). Depending on business requirements, a single Stored Procedure can return differe…
Recently we ran in to an issue while running some SQL jobs where we were trying to process the cubes.  We got an error saying failure stating 'NT SERVICE\SQLSERVERAGENT does not have access to Analysis Services. So this is a way to automate that wit…
Familiarize people with the process of retrieving data from SQL Server using an Access pass-thru query. Microsoft Access is a very powerful client/server development tool. One of the ways that you can retrieve data from a SQL Server is by using a pa…
Viewers will learn how to use the UPDATE and DELETE statements to change or remove existing data from their tables. Make a table: Update a specific column given a specific row using the UPDATE statement: Remove a set of values using the DELETE s…
Suggested Courses

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question