Count between two different dates from same column and table - sql

I have a table with this information
ACCTCCODE | ACCTDESCRIPTION | ISSUEDATE
----------+-----------------+----------------
1031 | Blahdescription | 2018-03-11
1032 | Blahdescription | 2017-04-18
1033 | Blahdescription | 2018-04-15
1034 | Blahdescription | 2018-011-04
I want to try and get the dates between two times? For two separate columns. E.g.
ACCTCCODE | ACCTDESCRIPTION | FIRSTCOUNT | SECOUNDCOUNT
----------+-----------------+-------------+--------------
1031 | Blahdescription | 150 23
1032 | Blahdescription | 75 101
1033 | Blahdescription | 3 78
1034 | Blahdescription | 11 23
I've tried to create a query with a SELECT within a SELECT but am new to sql so having a bit of trouble making it work.
Here's what I've come up with which works for first count but doesn't work quite right for the second count.
SELECT DISTINCT
account AS ACCTCODE, Description AS ACCTDESCRIPTION,
COUNT(issueDate) AS FIRSTCOUNT,
(SELECT COUNT(issueDate)
FROM Table1
WHERE issueDate BETWEEN CONVERT(DATETIME, '2018-2-31')
AND CONVERT(DATETIME, '2018-04-03')
AND account <> '') AS SECONDCOUNT
FROM
Table1
WHERE
issueDate BETWEEN CONVERT(DATETIME, '2017-11-31')
AND CONVERT(DATETIME, '2018-02-01')
AND account <> ''
GROUP BY
account, Description
ORDER BY
account, Description ASC

Use SUM() with CASE once for each date interval
SELECT account AS ACCTCODE, description AS ACCTDESCRIPTION,
SUM(CASE WHEN issuedate BETWEEN CONVERT(DATE, '20171131', 112) AND CONVERT(DATE, '20180201', 112)
THEN 1 ELSE 0 END) as FIRSTCOUNT,
SUM(CASE WHEN issuedate BETWEEN CONVERT(DATE, '20180228', 112) AND CONVERT(DATE, '20180403', 112)
THEN 1 ELSE 0 END) as SECONDCOUNT
FROM Table1
GROUP BY account, description

you can try like below by using case when
select ACCTCCODE,ACCTDESCRIPTION ,sum(case when issueDate>='2017-11-31' and issueDate<='2018-02-01' then 1 else 0 end)
as FIRSTCOUNT ,count(*) as SECOUNDCOUNT
FROM Table1
group by ACCTCCODE,ACCTDESCRIPTION

Related

How to perform group by in SQL Server for specific output

I have a table with few records, I want to get month wise data along with count on one of the column. The output should contain Month and count of Isregistered flag.
Table structure
| Inserted On | IsRegistered |
+-------------+--------------+
| 10-01-2020 | 1 |
| 15-01-2020 | 1 |
| 17-01-2020 | null |
| 17-02-2020 | 1 |
| 21-02-2020 | null |
| 04-04-2020 | null |
| 18-04-2020 | null |
| 19-04-2020 | 1 |
Excepted output
| Inserted On | Registered | Not Registered
+-------------+------------+---------------
| Jan | 2 | 1
| Feb | 1 | 1
| Apr | 1 | 2
I tried by performing normal group by but didn't got desired output
SELECT
DATENAME(MONTH, dateinserted) AS [MonthName], COUNT(ISRegistered)
FROM
tablename
GROUP BY
(DATENAME(MONTH, dateinserted))
Note: here null is treated as not registered
You can use aggregation. I would include the year and use the month number rather than name, so:
select year(inserted_on), month(inserted_on),
coalesce(sum(is_registered), 0) as num_registered,
sum(case when is_registered is null then 1 else 0 end) as num_not_registered
from tablename
group by year(inserted_on), month(inserted_on)
order by year(inserted_on), month(inserted_on);
Note: If you really want the monthname and want to combine data from different years (which seems unlikely, but . . . ), then you can use:
select datename(month, inserted_on),
coalesce(sum(is_registered), 0) as num_registered,
sum(case when is_registered is null then 1 else 0 end) as num_not_registered
from tablename
group by datename(month, inserted_on)
order by month(min(inserted_on));
The GROUP BY should include both the year and month (so there's no overlapping) as well as the DATENAME (for display). Something like this
drop table if exists #tablename;
go
create table #tablename(dateinserted date, ISRegistered int);
insert #tablename values
('2020-12-01', 0),
('2020-11-02', 1),
('2020-11-03', 1),
('2020-12-01', 1),
('2020-12-03', 1),
('2020-11-02', 0);
select year(dateinserted) yr,
datename(month, dateinserted) AS [MonthName],
sum(ISRegistered) Registered ,
sum(1-ISRegistered) [Not Registered]
from #tablename
group by year(dateinserted), month(dateinserted), datename(month, dateinserted)
order by year(dateinserted), month(dateinserted);
yr MonthName Registered Not Registered
2020 November 2 1
2020 December 2 1

Calculate data in Pivot

I have the following SQL table with 4 columns.
Table Name: tblTimeTransaction
Columns: EmployeeNumber, TransactionDate, CodeType, TimeShowninSeconds
CodeType has values : REG, OT1, OT2, OT3 respectively
I want it to show like this using pivot using 15 days incrementals starting from Jan 1 2020 onwards:
Employee Number | Effective Date | REG | OT1 | OT2 | OT3
E12345 | Between 10-1 till 10-15 | 200 | 100 | 50 | 45
E15000 | Between 10-1 till 10-15 | 400 | 600 | 903 | 49
E12345 | Between 10-15 till 10-31 | 200 | 100 | 50 | 45
E15000 | Between 10-15 till 10-31 | 400 | 600 | 903 | 49
E12346 | Between 11-1 till 11-15 | 4200 | 100 | 50 | 45
E15660 | Between 11-1 till 11-15 | 1200 | 600 | 6903 | 49
My SQL Code so far:
SELECT
Employee Number,
[TransactionDate] as [Effective Date],
[REG],
[OT1],
[OT2],
[OT3]
FROM
( SELECT Employee Number, TransactionDate, CodeType, TimeInSeconds
FROM [tblTimetransaction]
) ps
PIVOT
( SUM (TimeInSeconds)
FOR CodeType IN ( [REG], [OT1], [OT2], [OT3])
) AS pvt
where TransactionDate between '2020-01-01' and '2020-12-31'
If I follow you correctly, you can truncate the effective_date to either the 1st of 15th of the month depending on their day of the month, then use conditional aggregation to compute the total time_in_seconds for each code_type:
select employee_number,
datefromparts(year(effective_date), month(effective_date), case when day(effective_date) < 15 then 1 else 15 end) as dt,
sum(case when code_type = 'REG' then time_in_seconds else 0 end) as reg,
sum(case when code_type = 'OT1' then time_in_seconds else 0 end) as ot1,
sum(case when code_type = 'OT2' then time_in_seconds else 0 end) as ot2,
sum(case when code_type = 'OT3' then time_in_seconds else 0 end) as ot3
from tblTimetransaction
where effective_date >= '20200101' and effective_date < '20210101'
group by employee_number,
datefromparts(year(effective_date), month(effective_date), case when day(effective_date) < 15 then 1 else 15 end)

I'm getting unexpected results when I use SUM(CASE WHEN .... THEN "column_name") in sqlite3

I am trying to find the number of orders I got in the month of April. I have 3 orders but my query gets the result 0. What could be the problem?
Here's the table:
id | first | middle | last | product_name | numberOut | Date
1 | Muhammad | Sameer | Khan | Macbook | 1 | 2020-04-01
2 | Chand | Shah | Khurram | Dell Optiplex | 1 | 2020-04-02
3 | Sultan | | Chohan | HP EliteBook | 1 | 2020-03-31
4 | Express | Eva | Plant | Dell Optiplex | 1 | 2020-03-11
5 | Rana | Faryad | Ali | HP EliteBook | 1 | 2020-04-02
And here's the query:
SELECT SUM(CASE WHEN strftime('%m', oDate) = '04' THEN 'id' END) FROM orders;
If you want all Aprils, then you can just look at the month. I would recommend:
select count(*)
from orders o
where o.date >= '2020-04-01' and o.date < '2020-05-01';
Note that this does direct comparisons of date to a valid dates in the where clause.
The problem with your code is this:
THEN 'id'
You are using the aggregate function SUM() and you sum over a string literal like 'id' which is implicitly converted to 0 (because it can't be converted to a number) so the result is 0.
Even if you remove the single quotes you will not get the result that you want because you will get the sum of the ids.
But if you used:
THEN 1 ELSE 0
then you would get the correct result.
But with SQLite you can write it simpler:
SELECT SUM(strftime('%m', oDate) = '04') FROM orders;
without the CASE expression.
Or since you just want to count the orders then COUNT() will do it:
SELECT COUNT(*) FROM orders WHERE strftime('%m', oDate) = '04';
Edit.
If you want to count the orders for all the months then group by month:
SELECT strftime('%Y-%m', oDate) AS month,
COUNT(*) AS number_of_orders
FROM orders
GROUP BY month;
SELECT SUM(CASE WHEN strftime('%m', oDate) = '04' THEN 1 ELSE 0 END) FROM orders;
if you need to use SUM
There is a problem with your query. You do not need to do that aggregation operation.
SELECT COUNT(*) from table_name WHERE strftime('%m', Date) = '04';
I would use explicit date comparisons rather than date functions - this makes the query SARGeable, ie it may benefit an existing index.
The most efficient approach, with a filter in the where clause:
select count(*) cnt
from orders
where oDate >= '2020-04-01' and oDate < '2020-05-01'
Alternatively, if you want a result of 0 even when there are no orders in April you can do conditional aggregation, as you originally intended:
select sum(case when oDate >= '2020-04-01' and oDate < '2020-05-01' then 1 else 0 end) cnt
from orders

Summing By Count

I'm trying to create a Summation based on the Count number for a particular column. If you looks at the last line in the Select below you'll see that I tried implementing a CASE statement. However, it produces all NULL values. Which I believe I understand why (each row has a unique set of values) but I'm not sure how to fix my problem.
SELECT
TotalFilesProduced.ReviewDate,
TotalFilesProduced.FileReviewedByUserID,
TotalFilesProduced.FileSource,
TotalFilesProduced.FilesIndexed TotalIndexed,
TotalFilesProduced.FileNumberofPages TotalFileNumberofPages,
TotalFilesProduced.FilesProduced,
CASE WHEN COUNT(DISTINCT FileReviewedByUserID) > 1 THEN SUM(TotalFilesProduced.FilesIndexed) END
FROM
(SELECT
CAST(ibfp.FileReviewedDate AS DATE) ReviewDate,
ibfp.FileReviewedByUserID,
FileSource,
COUNT(*) FilesProduced,
COUNT(DISTINCT ibf.InboundFileID) FilesIndexed,
SUM(CASE WHEN ibfp.FromPage = ibfp.ToPage THEN 1
ELSE ibfp.ToPage-ibfp.FromPage + 1 END) [FileNumberofPages]
FROM
dbo.InboundFilePartitions ibfp
INNER JOIN dbo.InboundFiles ibf ON ibfp.InboundFileID = ibf.InboundFileID
WHERE
CAST(ibfp.FileReviewedDate AS DATE) >= '10/22/2014'
and CAST(ibfp.FileReviewedDate AS DATE) <= '10/22/2014'
and ibf.ProjectID in (110)
GROUP BY
CAST(ibfp.FileReviewedDate AS DATE),
ibfp.FileReviewedByUserID,
FileSource
) TotalFilesProduced
GROUP BY
TotalFilesProduced.ReviewDate,
TotalFilesProduced.FileReviewedByUserID,
TotalFilesProduced.FileSource,
TotalFilesProduced.FilesIndexed,
TotalFilesProduced.FileNumberofPages,
TotalFilesProduced.FilesProduced
Here is an example for further clarification - here the UserID 1036 producing a NULL is fine since it appear only once but for 804 - I would like to sum the TotalIndexed column so the NULL area should read 139 (for both instances that 804 appears)
ReviewDate | FilereviewedByUserID | FileSource | TotalIndexed | TotalFileNumberofPages | FilesProduced | (No Column Name) /*My Sum*/
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 804 | 1 | 1 | 67 | 1 | NULL
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 1036 | 1 | 1 | 17 | 1 | NULL
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 804 | 2 | 138 | 3322 | 184 | NULL
As stated in the comment
This will always be false
CASE WHEN COUNT(DISTINCT FileReviewedByUserID) > 1
Because of
GROUP BY ibfp.FileReviewedByUserID
And you have some other strange stuff
CAST(ibfp.FileReviewedDate AS DATE) >= '10/22/2014'
and CAST(ibfp.FileReviewedDate AS DATE) <= '10/22/2014'
is the same as
CAST(ibfp.FileReviewedDate AS DATE) = '10/22/2014'
More strange stuff
SUM(CASE WHEN ibfp.FromPage = ibfp.ToPage THEN 1
ELSE ibfp.ToPage-ibfp.FromPage + 1 END) [FileNumberofPages]
is the same as
SUM(ibfp.ToPage-ibfp.FromPage + 1) [FileNumberofPages]
not sure what you are trying to do but a group by on a group by is not common

Select most the recent event date for a specific event type from a related table

I have two tables, Case and CaseEvents.
The events are basically a user updating a case and there are lots of different types of event.
I have a KPI that two of those events (which are different types) have to have happened within 3 minutes - the Response Time.
Response Time is calculated by subtracting the date in EventTypeRef 1 from the date in EventTypeRef 2 OR EventTypeRef 3.
I include my desired result in the table below.
Apologies if this is simple, I'm a right newbie and couldn't find anything online that was similar (though maybe I was using the wrong terminology in my searches). Thanks for your help.
I am using SQL Server 2005
'Case table'
----------
CaseRef | CaseNo
1 | 1001
2 | 1002
CaseEvents table
----------------
CaseRef | EventType | EventStartDate | EventTypeRef
1 | 'LTE Detected' | 01/11/2013 09:05:36 | 1
1 | 'Ambulance called' | 01/11/2013 09:06:27 | 2
2 | 'LTE Detected' | 02/11/2013 09:11:22 | 1
2 | 'Patient will call ambulance' | 02/11/2013 09:13:01 | 3
1 | 'Case updated' | 01/11/2013 09:09:34 | 4
1 | 'Case marked complete' | 01/11/2013 09:13:34 | 5
Desired result
--------------
CaseNo | LTEDetected | 'LTE Acted On' | 'Response time' |
1 | 01/11/2013 09:05:36 | 01/11/2013 09:06:27 | 00:00:51 |
2 | 02/11/2013 09:11:22 | 02/11/2013 09:13:01 | 00:01:39 |
You can put a CASE statement within an aggregate, so you are only checking the event types you are interested in.
SELECT c.CaseNo,
LTEDetected = MIN(CASE WHEN ce.EventTypeRef = 1 THEN ce.EventStartDate END),
LTEActedOn = MIN(CASE WHEN ce.EventTypeRef IN (2, 3) THEN ce.EventStartDate END),
Responsetime = DATEDIFF(SECOND,
MIN(CASE WHEN ce.EventTypeRef = 1 THEN ce.EventStartDate END),
MIN(CASE WHEN ce.EventTypeRef IN (2, 3) THEN ce.EventStartDate END)
)
FROM Case c
INNER JOIN CaseEvents ce
ON c.CaseRef = ce.CaseRef
GROUP BY c.CaseNo;
Example on SQL Fiddle
select CaseRef
, datediff(second, StartDt, EndDt) as ResponseTime
from (
select CaseRef
, max(case when EventTypeRef = 1 then EventStartDate end) as StartDt
, min(case when EventTypeRef in (2,3) then EventStartDate end) as EndDt
from CaseEvents
group by
CaseRef
) as SubQueryAlias