Suppose I have a data table with the following fields:
CUSTOMER: either A or B
DAY: either Monday or Tuesday
PAID: either Y or N
The total number of rows being four, let's say the data table is this:
CUSTOMER DAY PAID
A Monday Y
A Tuesday N
B Monday Y
B Tuesday N
How do I create a SQL query on Teradata SQL Assistant, that will show the number of people who were Y on Monday and N on Tuesday? (or any of these combinations) I tried to use the query below, but cannot seem to figure out the logic. Your help is much appreciated!
SELECT DAY,
COUNT(CASE PAID WHEN 'Y' THEN CUSTOMER ELSE 0 END) AS PAID_CUSTOMERS,
COUNT(CASE WHEN PAID = 'Y' AND DAY = 'Monday' AND DAY = 'Tuesday' AND PAID = 'N' THEN CUSTOMER ELSE 0 END) AS CUSTOMERS_YM_NT
FROM T1
GROUP BY 1
ORDER BY 1
So, break each day down into a separate case statement:
case when DAY = 'Monday' and PAID = 'NO' then 'NO' else 'YES' end as Monday,
case when DAY = 'Tuesday' and PAID = 'NO' then 'NO' else 'YES end as Tuesday,
etc
Then, you can wrap that with another select and apply whatever criteria you want:
select
<whatever columns>
from
(select
case when DAY = 'Monday' and PAID = 'NO' then 'NO' else 'YES' end as Monday,
case when DAY = 'Tuesday' and PAID = 'NO' then 'NO' else 'YES end as Tuesday,
...
) t
where Monday 'YES'
and Tuesday = 'YES'
Related
I am using Teradata. The query below runs, but somehow, I cannot get it to calculate at each hospital admission looking back to previous row if the admission is to an ED and if so is it within 1 day. It works if I limit my data to a single MEMBER_NO and there is one Hospital admission, but when there are several over a few years, it will not give me "1" in "ED Visit within 1 Day of this Hospital Admit" column. Also, I am not able to get it Null at each start of MEMBER_NO for the "Previous LOCATION" and Null at the end for the "Next LOCATION."
SELECT js.*
,CASE
WHEN LOCATION = 'Hospital'
THEN Count(CASE WHEN LOCATION = 'Hospital' AND "Days Since ED Discharge" <= 1 THEN 1 END)
Over (PARTITION BY TRIM(MEMBER_NO)
ORDER BY DISCHARGE_DATE, ADMIT_DATE
RESET WHEN LOCATION = 'HOSPITAL')
END AS "ED Visit within 1 Day of this Hospital Admit"
,CASE
WHEN LOCATION = 'Hospital'
THEN Count(CASE WHEN LOCATION = 'Nursing Facility' AND "Days Since Last Hospital Discharge" <= 7 THEN 1 END)
Over (PARTITION BY TRIM(MEMBER_NO)
ORDER BY DISCHARGE_DATE, ADMIT_DATE
RESET WHEN LOCATION = 'HOSPITAL')
END AS "Nursing Facility Admit within 7 Days after this Hospital Discharge"
FROM
(
SELECT CLIENT, TRIM(MEMBER_NO) "MEMBER ID", AGE, ADMIT_NO, LOCATION, ADMIT_DATE, DISCHARGE_DATE
, COALESCE(MIN(LOCATION) over (order by ADMIT_NO rows between 1 preceding and 1 preceding), LOCATION) "Previous LOCATION"
, COALESCE(MIN(LOCATION) over (order by ADMIT_NO rows between 1 following and 1 following), LOCATION) "Next LOCATION"
,CASE
WHEN LOCATION = 'Hospital'
THEN ADMIT_DATE -
MIN(CASE WHEN LOCATION = 'ED' THEN DISCHARGE_DATE END)
Over (PARTITION BY TRIM(MEMBER_NO)
ORDER BY DISCHARGE_DATE, ADMIT_DATE
ROWS Unbounded Preceding)
END AS "Days Since ED Discharge"
,CASE
WHEN LOCATION <> 'Hospital'
THEN ADMIT_DATE -
Max(CASE WHEN LOCATION = 'Hospital' THEN DISCHARGE_DATE END)
Over (PARTITION BY TRIM(MEMBER_NO)
ORDER BY DISCHARGE_DATE, ADMIT_DATE
ROWS Unbounded Preceding)
END AS "Days Since Last Hospital Discharge"
FROM CLAIMS_DB.FACILITY_CLAIMS
WHERE ADMIT_DATE BETWEEN DATE '2017-01-01' AND DATE '2020-12-31'
) AS js;
Here is the display of the result of the query now. The cells shaded in red are incorrect. J6 should be "0" and L6 should be "1". As stated earlier, if I change the date range to only have one Hospital location reported then J6 works. Also, F2 and G8 should be Null.
Solution for properly calculating the "Days since ED Visit" at each Hospital Admit date is:
,CASE
WHEN LOCATION = 'Hospital'
THEN ADMIT_DATE -
MAX(CASE WHEN LOCATION = 'ED' THEN DISCHARGE_DATE END)
Over (PARTITION BY TRIM(MEMBER_NO)
ORDER BY DISCHARGE_DATE, ADMIT_DATE
ROWS Unbounded Preceding)
END AS "Days Since ED Discharge"
And the solution to getting Previous and Next Locations correct even for NULLs is not to use COALESCE, but instead do this:
, MIN(LOCATION) OVER (PARTITION BY MEMBER_NO ORDER BY ADMIT_NO ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) "Previous LOCATION"
, MIN(LOCATION) OVER (PARTITION BY MEMBER_NO ORDER BY ADMIT_NO ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) "Next LOCATION"
How to count days between date range with a specific day?
Example:
START_DT = January 1, 2014;
END_DT = January 31, 2014;
Day = :SampleDay
Sample Result:
Monday = 4,
Tuesday = 4,
Wednesday = 5
Please help. :|
Are you looking for something like this,
WITH t(date1, date2) AS
(
SELECT to_date('01/01/2014', 'dd/mm/yyyy'),
to_date('31/01/2014','dd/mm/yyyy')+1 -- Adding 1 to calculate the last day too.
FROM DUAL
)
SELECT count(days) day_count, day
DAY
FROM(
SELECT date1 + LEVEL -1 days,
to_char(date1 + LEVEL -1, 'FmDay') DAY, --Use `FmDay`, this will remove the Embedded spaces.
to_char(date1 + LEVEL -1, 'D') DAY#
FROM t
CONNECT BY LEVEL <= date2 - date1
)
WHERE day = 'Monday' --Filter with day, if you want to get the count for a specific day.
GROUP BY DAY, day#
ORDER BY day#;
You wont have a direct solution to this. In oracle you have this form to know what day of the week is a specific date:
to_char(to_date('01012014', 'ddmmyyyy'), 'Day')
I would recommend to you to make a store procedure with a simple algorithm which receive that three parameters and then display the information you need. Put it in a query and it is done.
The Problem: Given a day of the week (1, 2, 3, 4, 5, 6, 7), a starting date and an ending date, compute the number of times the given day of the week appears between the starting and ending dates not inclusive of a date for which there were no sales.
Context:
Table "Ticket" has the following structure and sample content:
i_ticket_id c_items_total dt_create_time dt_close_time
----------------------------------------------------------------------------
1 8.50 '10/1/2012 10:23:00' '10/1/2012 11:05:05'
2 10.50 '10/1/2012 11:00:00' '10/1/2012 11:45:05'
3 8.50 '10/2/2012 08:00:00' '10/2/2012 09:25:05'
4 8.50 '10/4/2012 08:00:00' '10/4/2012 09:25:05'
5 7.50 '10/5/2012 13:22:23' '10/5/2012 14:33:27'
.
.
233 6.75 '10/31/2012 23:20:00' '10/31/2012 23:55:39'
Details
There may or may not be any tickets for one or more days during a month. (i.e. the place was closed that/those day/s)
Days in which the business is closed are not regular. There is no predictable pattern.
Based on Get number of weekdays (Sundays, Mondays, Tuesdays) between two dates SQL,
I have derived a query which returns the number of times a given day of the week occurs between the start date and the end date:
DECLARE #dtStart DATETIME = '10/1/2013 04:00:00'
DECLARE #dtEnd DATETIME = '11/1/2013 03:59:00'
DECLARE #day_number INTEGER = 1
DECLARE #numdays INTEGER
SET #numdays = (SELECT 1 + DATEDIFF(wk, #dtStart, #dtEnd)-
CASE WHEN DATEPART(weekday, #dtStart) #day_number THEN 1 ELSE 0 END -
CASE WHEN DATEPART(weekday, #dtEnd) <= #day_number THEN 1 ELSE 0 END)
Now I just need to filter this so that any zero-dollar days are not included in the count. Any help you can provide to add this filter based on the contents of the tickets table is greatly appreciated!
If I understand correctly, you can use a calendar table to count the number of days where the day of week is n and between the start and end and is a date that has ticket sales, which I guess is when the date exists in tickets and has the sum(c_items_total) > 0
WITH cal AS
(
SELECT cast('2012-01-01' AS DATE) dt, datepart(weekday, '2012-01-01') dow
UNION ALL
SELECT dateadd(day, 1, dt), datepart(weekday, dateadd(day, 1, dt))
FROM cal
WHERE dt < getdate()
)
SELECT COUNT(1)
FROM cal
WHERE dow = 5
AND dt BETWEEN '2012-04-01' AND '2012-12-31'
AND EXISTS (
SELECT 1
FROM tickets
WHERE cast(dt_create_time AS DATE) = dt
GROUP BY cast(dt_create_time AS DATE)
HAVING sum(c_items_total) > 0
)
OPTION (MAXRECURSION 0)
SQLFiddle
I am having some trouble with doctrine2. I want to order a query but by day of the week.
What do I mean:
If where the day of the date given is Tuesday, I want to have it ordered by Tuesday, Wednseday, ..., Sunday, Monday.
But an performance can have multiple days.
The code I got here does the trick for the order by
public function getValidPerformancesByDay2($date, $max = 25, $from, $asSql = false){
$myday = intVal(date('w',strtotime($date)));
$q = $this->getEntityManager()
->createQueryBuilder()
->select('DISTINCT textdesc,
CASE WHEN (perfdays.id < '. $myday .') THEN perfdays.id + 8
ELSE perfdays.id END AS HIDDEN sortvalue')
->from ('sys4winsegundaBundle:Performance','textdesc')
->join('textdesc.days', 'perfdays')
->where ('textdesc.enddate >= :date')
->andWhere('textdesc.isvalid = true')
->orderBy('sortvalue','ASC')
->setMaxResults($max)
->setFirstResult($from)
->setParameter('date',$date)
;
$query = $q->getQuery();
if ($asSql){
return $query;
}
return $query->getResult();
}
But unfortunately, when I look at the query that has been sent it is:
SELECT DISTINCT p0_.id AS id0, p0_.name AS name1, p0_.duration AS duration2,
p0_.addedby AS addedby3, p0_.startdate AS startdate4, p0_.enddate AS enddate5,
p0_.starthour AS starthour6, p0_.flyer AS flyer7, p0_.price AS price8,
p0_.discount AS discount9, p0_.isvalid AS isvalid10,
p0_.archivedon AS archivedon11, p0_.description AS description12,
p0_.weblink AS weblink13, p0_.techinfo AS techinfo14, p0_.slug AS slug15,
CASE WHEN (d1_.id < 4) THEN d1_.id + 8 ELSE d1_.id END AS sclr16,
p0_.place_id AS place_id17, p0_.gallery_id AS gallery_id18 FROM performances
p0_ INNER JOIN performance_day p2_ ON p0_.id = p2_.performance_id
INNER JOIN days d1_ ON d1_.id = p2_.day_id WHERE p0_.enddate >= ? AND
p0_.isvalid = 1 ORDER BY sclr16 ASC OFFSET 0
Parameters: ['2012-08-23']
Time: 5.13 ms
Which means that if a performance occurred 3 times a week, I get 3 occurrences.
anyone got an idea?
EDIT
my english being pretty bad, i lltry to explain it differently:
Well i got art performances that occurs on various days.
What i want to do is order them by nearest occurence in time.
But the way i sent it to database is with a startdate, an enddate and then what days it occurs (Tuesday, wednesday...)
My query does this( ordering by nearest one) but as some performance occured for example on wednesdays y fridays, my query will return that performance 2 times (on for wednsday and the other one for friday) while i should only retrieve on occurance of each performance but with the same order (nearest first)
If you want 1 occurrence per week use
$q->groupBy()
For the date converted to week number. And use count() in your select. I'm not sure that I Understand your question.
I'm trying to get a query to summarize each employees work for the week. For example, John Doe did a total of 12 tickets for the week, 4 of which were Break/Fixes, and 4 were Enhancement, and another 4 were uncategorized.
This is what I have so far:
SELECT (users.first_name || ' ' || users.last_name) AS Name,
COUNT(tickets.id) AS 'Number of Tickets Closed',
COUNT(tickets.category = 'Maintenance') AS 'Maintenance Tickets',
COUNT(tickets.category = 'After Hours') AS 'After Hours Tickets',
COUNT(tickets.category = 'Break Fix') AS 'Break Fix Tickets',
COUNT(tickets.category = 'Enhancement') AS 'Enhancement Tickets',
COUNT(tickets.category = '') AS 'Non Categorized Tickets'
FROM tickets, users
ON tickets.assigned_to=users.id
WHERE (tickets.status = 'closed') AND
(tickets.closed_at >= '2011-07-16 00:00:00') AND
(tickets.closed_at <= '2011-07-22 23:59:59')
GROUP BY Name;
Here is a sample result:
John Doe1 10 10 10 10 10 10
John Doe2 2 2 2 2 2 2
John Doe3 25 24 24 24 24 24
John Doe4 2 2 2 2 2 2
John Doe5 12 10 10 10 10 10
John Doe6 7 7 7 7 7 7
This query doesn't quite work as I expected it to as all of the columns have the same total (The total number of tickets closed, the following columns seems to only contain the categorized ones.) Help?
EDIT
Just wanted to post the functional code:
SELECT (users.first_name || ' ' || users.last_name) AS Name,
COUNT(tickets.id) AS 'Number of Tickets Closed',
COUNT(case tickets.category when 'Maintenance' then 1 else null end) AS 'Maintenance Tickets',
COUNT(case tickets.category when 'After Hours' then 1 else null end) AS 'After Hours Tickets',
COUNT(case tickets.category when 'Break Fix' then 1 else null end) AS 'Break Fix Tickets',
COUNT(case tickets.category when 'Enhancement' then 1 else null end) AS 'Enhancement Tickets',
COUNT(case tickets.category when '' then 1 else null end) AS 'Non Categorized Tickets'
FROM tickets, users
ON tickets.assigned_to=users.id
WHERE (tickets.status = 'closed') AND
(tickets.closed_at >= '2011-07-16') AND
(tickets.closed_at <= '2011-07-22')
GROUP BY Name;
you may want to use COUNT like this
...
COUNT(case tickets.category when 'Maintenance' then 1 else null end),
COUNT(case tickets.category when 'After Hours' then 1 else null end),
...
It seems to me you cannot use an alias in the GROUP BY clause. Don't your users have an ID you could use to differenciate them?
And you must use SUM instead of COUNT if you want to count compared with a condition.
SELECT (users.first_name || ' ' || users.last_name) AS Name,
COUNT(tickets.id) AS 'Number of Tickets Closed',
SUM(tickets.category = 'Maintenance') AS 'Maintenance Tickets',
SUM(tickets.category = 'After Hours') AS 'After Hours Tickets',
SUM(tickets.category = 'Break Fix') AS 'Break Fix Tickets',
SUM(tickets.category = 'Enhancement') AS 'Enhancement Tickets',
SUM(tickets.category = '') AS 'Non Categorized Tickets'
FROM tickets, users
ON tickets.assigned_to=users.id
WHERE (tickets.status = 'closed') AND
(tickets.closed_at >= '2011-07-16 00:00:00') AND
(tickets.closed_at <= '2011-07-22 23:59:59')
GROUP BY Name;