SQL: Get SUM of grouped query having count statement - sql

I'm looking for a query that counts all entries which have more than 1 entry.
e.g.:
adrnr value datum
15 8.68 2021-08-29
10 16.4 2021-08-30
15 33.6 2021-08-30
16 125.98 2021-08-31
10 23.44 2021-08-31
18 19.87 2021-08-31
16 26.87 2021-09-01
10 10.0 2021-09-01
I came up with following query:
SELECT adrnr, COUNT(adrnr) as summe FROM tablename WHERE datum >= '2021-01-08 00:00:00.000'
AND datum <= '2021-31-08 23:59:59.999' group by adrnr having count(adrnr) > 1
I then get an answer:
adrnr summe
15 2
10 2
This is fine, but I want to get just one SUM of all entries, i.e.:
summe
4
How do I get this answer. And after that I want to get the the SUM of all values that depends on the same condition, i.e. 82.12
Any idea?
Regards Jens

Use a subquery against your current query:
SELECT SUM(summe)
FROM
(
SELECT COUNT(adrnr) AS summe
FROM tablename
WHERE datum >= '2021-08-01' AND datum < '2021-09-01'
GROUP BY adrnr
HAVING COUNT(drnr) > 1
) t;
Note: Your timestamp/date literals looked a bit off. The above assumes you only want to target the month of August, 2021.

Related

how to aggregate one record multiple times based on condition

I have a bunch of records in the table below.
product_id produced_date expired_date
123 2010-02-01 2012-05-31
234 2013-03-01 2014-08-04
345 2012-05-01 2018-02-25
... ... ...
I want the output to display how many unexpired products currently we have at the monthly level. (Say, if a product expires on August 04, we still count it in August stock)
Month n_products
2010-02-01 10
2010-03-01 12
...
2022-07-01 25
2022-08-01 15
How should I do this in Presto or Hive? Thank you!
You can use below SQL.
Here we are using case when to check if a product is expired or not(produced_date >= expired_date ), if its expired, we are summing it to get count of product that has been expired. And then group that data over expiry month.
select
TRUNC(expired_date, 'MM') expired_month,
SUM( case when produced_date >= expired_date then 1 else 0 end) n_products
from mytable
group by 1
We can use unnest and sequence functions to create a derived table; Joining our table with this derived table, should give us the desired result.
Select m.month,count(product_id) as n_products
(Select
(select x
from unnest(sequence(Min(month(produced_date)), Max(month(expired_date)), Interval '1' month)) t(x)
) as month
from table) m
left join table t on m.month >= t.produced_date and m.month <= t.expired_date
group by 1
order by 1

Fetching Date and year from Timestamp column (Athena)

I'm working in Athena (SQL) and trying to extract the date, year and month from column called "createddate" which involves timestamp and its a varchar data type. I have tried bunch of queries but I am getting errors after errors. Can you please help me extracting the date, year, month, week from this createddate column?
The field "createddate" is found in the following format:
id
createddate
1
11/29/2016 10:58:02
2
12/04/2016 07:07:58
3
10/22/2018 03:47:23
4
10/22/2018 08:20:25
5
10/22/2018 08:29:26
6
10/22/2018 08:42:28
7
10/22/2018 08:46:21
8
10/22/2018 10:18:57
12
10/22/2018 22:16:46
13
10/22/2018 22:24:33
14
10/23/2018 02:55:49
15
10/23/2018 07:49:39
16
10/23/2018 09:15:57
32
10/26/2018 06:19:13
33
10/26/2018 06:21:09
34
10/26/2018 06:24:59
48
10/30/2018 19:11:41
49
10/30/2018 20:10:10
64
11/01/2018 18:06:15
65
11/01/2018 18:08:00
66
11/01/2018 18:08:37
2
12/04/2016 07:07:58
99
11/09/2018 23:52:02
100
11/09/2018 23:57:13
Here are all my attempts:
select * from table where YEAR(from_iso8601_timestamp(createddate)) = 2022
and MONTH(from_iso8601_timestamp(createddate)) = 6 limit 10
select date_format(createddate,'%m/%d/%Y %H:%m:%s') from table limit 10
select date_format(createddate,'%m/%d/%Y H:m:s') from table limit 10
select date_format(createddate,'%m/%d/%Y %H:%i:%s') from table limit 10
select date_parse(createddate, '%m/%d/%Y %H:%i%p') from table limit 10
select date_parse(createddate, ' %m/%d/%Y') from table limit 10
select cast(date_parse(createddate,'%Y-%m-%d %h24:%i:%s') as date) from table limit 10
Select CAST(date_format(date_parse(cast(createddate as varchar(10)), '%m%d%Y'), '%m/%d/%Y') AS DATE) from table limit 10
Try with this one:
WITH cte AS (
SELECT id,
DATE_PARSE(createddate, '%m/%d/%Y %H:%i:%s') AS createddate
FROM table
)
SELECT id,
createddate,
YEAR(createddate),
MONTH(createddate),
WEEK(createddate)
FROM cte
You can find the documentation relative to the employed date functions here.

How to calculate total worktime per week [SQL]

I have a table of EMPLOYEES that contains information about the DATE and WORKTIME per that day. Fx:
ID | DATE | WORKTIME |
----------------------------------------
1 | 1-Sep-2014 | 4 |
2 | 2-Sep-2014 | 6 |
1 | 3-Sep-2014 | 5.5 |
1 | 4-Sep-2014 | 7 |
2 | 4-Sep-2014 | 4 |
1 | 9-Sep-2014 | 8 |
and so on.
Question: How can I create a query that would allow me to calculate amount of time worked per week (HOURS_PERWEEK). I understand that I need a summation of WORKTIME together with grouping considering both, ID and week, but so far my trials as well as googling didnt yield any results. Any ideas on this? Thank you in advance!
edit:
Got a solution of
select id, sum (worktime), trunc(date, 'IW') week
from employees
group by id, TRUNC(date, 'IW');
But will need somehow to connect that particular output with DATE table by updating a newly created column such as WEEKLY_TIME. Any hints on that?
You can find the start of the ISO week, which will always be a Monday, using TRUNC("DATE", 'IW').
So if, in the query, you GROUP BY the id and the start of the week TRUNC("DATE", 'IW') then you can SELECT the id and aggregate to find the SUM the WORKTIME column for each id.
Since this appears to be a homework question and you haven't attempted a query, I'll leave it at this to point you in the correct direction and you can complete the query.
Update
Now I need to create another column (lets call it WEEKLY_TIME) and populate it with values from the current output, so that Sep 1,3,4 (for ID=1) would all contain value 16.5, specifying that on that day (that is within the certain week) that person worked 16.5 in total. And for ID=2 it would then be a value of 10 for both Sep 2 and 4.
For this, if I understand correctly, you appear to not want to use aggregation functions and want to use the analytic version of the function:
select id,
"DATE",
trunc("DATE", 'IW') week,
worktime,
sum (worktime) OVER (PARTITION BY id, trunc("DATE", 'IW'))
AS weekly_time
from employees;
Which, for the sample data:
CREATE TABLE employees (ID, "DATE", WORKTIME) AS
SELECT 1, DATE '2014-09-01', 4 FROM DUAL UNION ALL
SELECT 2, DATE '2014-09-02', 6 FROM DUAL UNION ALL
SELECT 1, DATE '2014-09-03', 5.5 FROM DUAL UNION ALL
SELECT 1, DATE '2014-09-04', 7 FROM DUAL UNION ALL
SELECT 2, DATE '2014-09-04', 4 FROM DUAL UNION ALL
SELECT 1, DATE '2014-09-09', 8 FROM DUAL;
Outputs:
ID
DATE
WEEK
WORKTIME
WEEKLY_TIME
1
2014-09-01 00:00:00
2014-09-01 00:00:00
4
16.5
1
2014-09-03 00:00:00
2014-09-01 00:00:00
5.5
16.5
1
2014-09-04 00:00:00
2014-09-01 00:00:00
7
16.5
1
2014-09-09 00:00:00
2014-09-08 00:00:00
8
8
2
2014-09-04 00:00:00
2014-09-01 00:00:00
4
10
2
2014-09-02 00:00:00
2014-09-01 00:00:00
6
10
db<>fiddle here
edit: answer submitted without noticing "Oracle" tag. Otherwise, question answered here: Oracle SQL - Sum and group data by week
Select employee_Id,
DATEPART(week, workday) as [Week],
sum (worktime) as [Weekly Hours]
from WORK
group by employee_id, DATEPART(week, workday)
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=238b229156a383fa3c466b6c3c2dee1e

How do I extract the time-of-day from a date in Oracle SQL?

I have a SQL database of dates and times, but they are combined into a single value (called time). I would like to determine the number of entries per every hour, but I cannot figure out how to do this.
If I do:
Select time from time_table
The result I get is:
2016-05-13 07:23:23
2016-05-13 07:34:34
2016-05-14 07:21:00
2016-05-14 09:42:43
What I would like is either:
07:23:23
07:34:34
07:21:00
09:42:43
which I can sort to get:
07:21:00
07:23:23
07:34:34
09:42:43
Or, ultimately, I'd like to get counts:
07-08: 3
08-09: 0
09-10: 1
Is there any way to do this?
Time-of-day can be extracted from a value of DATE datatype by subtracting the truncation of that value:
select time - trunc(time) from.....
This will return a fractional number, >= 0 and < 1, representing a fraction of a day. To convert it to hour: multiply by 24.
For example, it is ~ 8:08 pm where I am right now. Then:
select 24 * (sysdate - trunc(sysdate)) as result from dual;
RESULT
----------
20.1566667
So now, if I want to know the hour, I can take trunc() again. Earlier I truncated a date; now the result is a number and I truncate a number.
Putting it all together (the first part generates the whole numbers from 0 to 23):
with h ( hr ) as (select level - 1 from dual connect by level <= 24)
select h.hr, count(tt.time) as ct
from h left outer join time_table tt on h.hr = trunc(24 * (tt.time - trunc(tt.time)))
group by h.hr
order by hr -- optional
;
You can format the "hour" column differently, although I don't see the point; my solution will show 8 where you show 08-09. Both have the same information.
Here is one solution with two sub-queries, one to generate a complete list of hours and one to generate a list of numbers in the target table. An outer join is necessary to produce zero counts for hours with no matches.
Note that bucket labels such as 7-8, 8-9 imply double counting, so I've ignored that in favour of single hours.
SQL> select * from t42
2 /
ID TCOL
---------- -------------------
1 2016-05-13 07:23:23
2 2016-05-13 07:34:34
3 2016-05-14 07:21:00
4 2016-05-14 09:42:43
SQL> with hrs as (select level-1 as hr
2 from dual
3 connect by level <= 24 )
4 , t as (select to_number(to_char(tcol, 'HH24')) as hr
5 from t42)
6 select hrs.hr
7 , count(t.hr)
8 from hrs
9 left outer join t
10 on hrs.hr = t.hr
11 where hrs.hr between 7 and 9
12 group by hrs.hr
13 order by hrs.hr
14 /
HR COUNT(T.HR)
---------- -----------
7 3
8 0
9 1
SQL>
This solution assumes the time column is an Oracle date datatype. If it's a string then either casting it to a date first or applying a substr() would work.
this will help you to solve you problem taken from
Counting number of records hour by hour between two dates in oracle
SELECT
trunc(time ,'HH'),
count(*)
FROM
time_table
WHERE
time > trunc(SYSDATE -2)
group by trunc(time ,'HH');
Result
2016-11-29 09:00:00.0 | 8 |

How to aggregate 7 days in SQL

I was trying to aggregate a 7 days data for FY13 (starts on 10/1/2012 and ends on 9/30/2013) in SQL Server but so far no luck yet. Could someone please take a look. Below is my example data.
DATE BREAD MILK
10/1/12 1 3
10/2/12 2 4
10/3/12 2 3
10/4/12 0 4
10/5/12 4 0
10/6/12 2 1
10/7/12 1 3
10/8/12 2 4
10/9/12 2 3
10/10/12 0 4
10/11/12 4 0
10/12/12 2 1
10/13/12 2 1
So, my desired output would be like:
DATE BREAD MILK
10/1/12 1 3
10/2/12 2 4
10/3/12 2 3
10/4/12 0 4
10/5/12 4 0
10/6/12 2 1
Total 11 15
10/7/12 1 3
10/8/12 2 4
10/9/12 2 3
10/10/12 0 4
10/11/12 4 0
10/12/12 2 1
10/13/12 2 1
Total 13 16
--------through 9/30/2013
Please note, since FY13 starts on 10/1/2012 and ends on 9/30/2012, the first week of FY13 is 6 days instead of 7 days.
I am using SQL server 2008.
You could add a new computed column for the date values to group them by week and sum the other columns, something like this:
SELECT DATEPART(ww, DATEADD(d,-2,[DATE])) AS WEEK_NO,
SUM(Bread) AS Bread_Total, SUM(Milk) as Milk_Total
FROM YOUR_TABLE
GROUP BY DATEPART(ww, DATEADD(d,-2,[DATE]))
Note: I used DATEADD and subtracted 2 days to set the first day of the week to Monday based on your dates. You can modify this if required.
Use option with GROUP BY ROLLUP operator
SELECT CASE WHEN DATE IS NULL THEN 'Total' ELSE CONVERT(nvarchar(10), DATE, 101) END AS DATE,
SUM(BREAD) AS BREAD, SUM(MILK) AS MILK
FROM dbo.test54
GROUP BY ROLLUP(DATE),(DATENAME(week, DATE))
Demo on SQLFiddle
Result:
DATE BREAD MILK
10/01/2012 1 3
10/02/2012 2 4
10/03/2012 2 3
10/04/2012 0 4
10/05/2012 4 0
10/06/2012 2 1
Total 11 15
10/07/2012 1 3
10/08/2012 4 7
10/10/2012 0 4
10/11/2012 4 0
10/12/2012 2 1
10/13/2012 2 1
Total 13 16
You are looking for a rollup. In this case, you will need at least one more column to group by to do your rollup on, the easiest way to do that is to add a computed column that groups them into weeks by date.
Take a lookg at: Summarizing Data Using ROLLUP
Here is the general idea of how it could be done:
You need a derived column for each row to determine which fiscal week that record belongs to. In general you could subtract that record's date from 10/1, get the number of days that have elapsed, divide by 7, and floor the result.
Then you can GROUP BY that derived column and use the SUM aggregate function.
The biggest wrinkle is that 6 day week you start with. You may have to add some logic to make sure that the weeks start on Sunday or whatever day you use but this should get you started.
The WITH ROLLUP suggestions above can help; you'll need to save the data and transform it as you need.
The biggest thing you'll need to be able to do is identify your weeks properly. If you don't have those loaded into tables already so you can identify them, you can build them on the fly. Here's one way to do that:
CREATE TABLE #fy (fyear int, fstart datetime, fend datetime);
CREATE TABLE #fylist(fyyear int, fydate DATETIME, fyweek int);
INSERT INTO #fy
SELECT 2012, '2011-10-01', '2012-09-30'
UNION ALL
SELECT 2013, '2012-10-01', '2013-09-30';
INSERT INTO #fylist
( fyyear, fydate )
SELECT fyear, DATEADD(DAY, Number, DATEADD(DAY, -1, fy.fstart)) AS fydate
FROM Common.NUMBERS
CROSS APPLY (SELECT * FROM #fy WHERE fyear = 2013) fy
WHERE fy.fend >= DATEADD(DAY, Number, DATEADD(DAY, -1, fy.fstart));
WITH weekcalc AS
(
SELECT DISTINCT DATEPART(YEAR, fydate) yr, DATEPART(week, fydate) dt
FROM #fylist
),
ridcalc AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY yr, dt) AS rid, yr, dt
FROM weekcalc
)
UPDATE #fylist
SET fyweek = rid
FROM #fylist
JOIN ridcalc
ON DATEPART(YEAR, fydate) = yr
AND DATEPART(week, fydate) = dt;
SELECT list.fyyear, list.fyweek, p.[date], COUNT(bread) AS Bread, COUNT(Milk) AS Milk
FROM products p
JOIN #fylist list
ON p.[date] = list.fydate
GROUP BY list.fyyear, list.fyweek, p.[date] WITH ROLLUP;
The Common.Numbers reference above is a simple numbers table that I use for this sort of thing (goes from 1 to 1M). You could also build that on the fly as needed.