Enumerating records by date - sql

Say we have 5 records for items sold on particular dates like this
Date of Purchase Qty
2016-11-29 19:33:50.000 5
2017-01-03 20:09:49.000 4
2017-02-23 16:21:21.000 11
2016-11-29 14:33:51.000 2
2016-12-02 16:24:29.000 4
I´d like to enumerate each record by the date in order with an extra column like this:
Date of Purchase Qty Order
2016-11-29 19:33:50.000 5 1
2017-01-03 20:09:49.000 4 3
2017-02-23 16:21:21.000 11 4
2016-11-29 14:33:51.000 2 1
2016-12-02 16:24:29.000 4 2
Notice how both dates on 2016-11-29 have the same order number because I only want to order the records by the date and not by the datetime. How would I create this extra column in just plain SQL?

Using dense_rank() and ordering by the date of DateOfPurchase
select *
, [Order] = dense_rank() over (order by convert(date,DateOfPurchase))
from t
rextester demo: http://rextester.com/FAAQL92440
returns:
+---------------------+-----+-------+
| DateOfPurchase | Qty | Order |
+---------------------+-----+-------+
| 2016-11-29 19:33:50 | 5 | 1 |
| 2016-11-29 14:33:51 | 2 | 1 |
| 2016-12-02 16:24:29 | 4 | 2 |
| 2017-01-03 20:09:49 | 4 | 3 |
| 2017-02-23 16:21:21 | 11 | 4 |
+---------------------+-----+-------+

Related

find holidays for persons work in some branches [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have 3 table of data: some people work in a branch and others work in 2 or more branch.
We define 2 case holiday: type 1 all branch is Closed and type 0 is some branch is Closed (not all).
Now I want to find person how is in holiday if all person-branch is Closed
Holiday
ID Date AllBranch
1 2019/02/01 1
2 2019/02/05 0
3 2019/02/06 0
BranchHoliday
ID HolidayID BranchID
1 2 2
2 2 3
3 3 2
PersonBranch
ID PersonID BranchID
1 10 2
2 11 2
3 11 3
4 12 2
5 12 4
The result I want is :
PersonID Hdate
10 2019/02/01
11 2019/02/01
12 2019/02/01
10 2019/02/05
11 2019/02/05
10 2019/02/06
In date (2019/02/01) AllBranch is 1 so all person is in holiday
In date (2019/02/05) AllBranch is 0 so:
PersonID-10 work only in BranchId 2 is define in BranchHoliday table so is in holiday
PersonID-11 work in 2 branch(2,3) and all 2,3 is define closed in BranchHoliday table so is in holiday
PersonID-12 work in 2 branch(2,4) and BranchId 4 is NOT define closed in BranchHoliday so is NOT in holiday
In date (2019/02/06) AllBranch is 0 so:
PersonID-10 work only in BranchId 2 and branch 2 is define in BranchHoliday table so is in holiday
PersonID-11 work in 2 branch(2,3) and only branch 3 is NOT define closed in BranchHoliday table so is in NOT holiday
PersonID-12 work in 2 branch(2,4) and branch 3 is NOT define closed in BranchHoliday table so is NOT in holiday
I need sql query and I am using SQL Server 2016
I don't know why you accepted Esteban's answer, given that your expected result is this. 6 rows only.
PersonID Hdate
10 2019/02/01
11 2019/02/01
12 2019/02/01
10 2019/02/05
11 2019/02/05
10 2019/02/06
Yet Esteban's query produces 7 rows. On February 6 holiday, it wrongly includes person #11 to allowed to have a holiday on February 6. It contradicts your problem definition:
In date (2019/02/06) AllBranch is 0 so:
* ...
* PersonID-11 work in 2 branch(2,3) and only branch 3 is NOT define closed
in BranchHoliday table so is in NOT holiday
Presumably, Person's BranchHoliday(s) should be checked(joined) against the Holiday's table, right? But Esteban's query is not doing that.
Esteban's query produces incorrect output:
Live test: http://sqlfiddle.com/#!18/86728/2
| PersonID | Date |
|----------|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
| 11 | 2019-02-06 |
And given these different data:
Holiday
ID Date AllBranch
1 2019/02/01 1
2 2019/02/05 0
3 2019/02/06 0
4 2019/04/02 0
BranchHoliday
ID HolidayID BranchID
1 2 2
2 2 3
3 3 2
4 4 2
5 4 4
Esteban's query produces incorrect output again:
Live test: http://sqlfiddle.com/#!18/10348/1
| PersonID | Date |
|----------|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 12 | 2019-02-05 |
| 10 | 2019-02-06 |
| 11 | 2019-02-06 |
| 12 | 2019-02-06 |
| 10 | 2019-04-02 |
| 11 | 2019-04-02 |
| 12 | 2019-04-02 |
It should produce this:
Live test: http://sqlfiddle.com/#!17/7b6be/1
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
| 10 | 2019-04-02 |
| 12 | 2019-04-02 |
And given these data. Note that only persons on branch #5 are allowed to have a holiday on April 2.
Holiday
ID Date AllBranch
1 2019/02/01 1
2 2019/02/05 0
3 2019/02/06 0
4 2019/04/02 0
BranchHoliday
ID HolidayID BranchID
1 2 2
2 2 3
3 3 2
4 4 5
Esteban's query produces incorrect output again, as only the persons on branch #5 are allowed to have a holiday on April 2. Yet his query includes persons that should not be allowed to have a holiday on April 2. Persons #10 and #11 are not included on branch #5, they should not be on April 2.
Live test: http://sqlfiddle.com/#!18/fd1d3/1
| PersonID | Date |
|----------|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
| 11 | 2019-02-06 |
| 10 | 2019-04-02 |
| 11 | 2019-04-02 |
It should produce this. No employees are allowed to have a holiday on April 2, even person #10 is not allowed to have a holiday on April 2, as person #10 is on branch #2 only. Only persons on branch #5 are allowed to have a holiday.
Live test: http://sqlfiddle.com/#!17/299f73/1
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
This is the correct query (Postgres version):
Live test: http://sqlfiddle.com/#!17/6cf97/2
select h.date, p.id
from holiday h
cross join person p
join personbranch pb
on p.id = pb.personid
left join branchholiday bh
on h.id = bh.holidayid and pb.branchid = bh.branchid
group by h.date, p.id
having
every(h.allbranch)
or
-- choose only every person whose branch ids are all present in branchholiday
-- filtered by holidayid from holiday.id
every(bh.branchid is not null)
order by h.date, p.id
Output matches your problem definition's expected output:
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
SQL Server version:
Live test: http://sqlfiddle.com/#!18/41a54/3
select p.id, h.date
from holiday h
cross join person p
join personbranch pb
on p.id = pb.personid
left join branchholiday bh
on h.id = bh.holidayid and pb.branchid = bh.branchid
group by h.date, p.id
having
count(case when h.allbranch = 1 then 1 end) = count(*)
or
-- choose only every person whose branch ids are all present in branchholiday
-- filtered by holidayid from holiday.id
count(case when bh.branchid is not null then 1 end) = count(*)
order by h.date, p.id
Output matches your problem definition's expected output:
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
This is another SQL Server's every idiom. You can change the count(condition) = count(*) to min approach:
Live test: http://sqlfiddle.com/#!18/41a54/4
having
min(case when h.allbranch = 1 then 1 else 0 end) = 1
or
-- choose only every person whose branch ids are all present in branchholiday
-- filtered by holidayid from holiday.id
min(case when bh.branchid is not null then 1 else 0 end) = 1
Output matches your problem definition's expected output:
| id | date |
|----|------------|
| 10 | 2019-02-01 |
| 11 | 2019-02-01 |
| 12 | 2019-02-01 |
| 10 | 2019-02-05 |
| 11 | 2019-02-05 |
| 10 | 2019-02-06 |
One solution would be to break it into two parts:
First selecting the persons for the AllBranch holidays, in a second turn selecting the persons for the specific holidays, where all branches they're working in, have a defined holiday:
SELECT AllPers.PersonID, H.Date
FROM Holiday H
INNER JOIN (
SELECT DISTINCT PersonID
FROM PersonBranch
) AllPers ON H.AllBranch = 1
UNION
SELECT Sub.PersonID, H.Date
FROM Holiday H
INNER JOIN (
SELECT PB.PersonID
, SUM(IIF(BH.BranchID IS NULL, 1, 0)) AS AnyBranchOpen
FROM PersonBranch PB
LEFT JOIN BranchHoliday BH ON PB.BranchID = BH.BranchID
GROUP BY PB.PersonID
) Sub ON AnyBranchOpen = 0
WHERE H.AllBranch = 0

Weekly Average Reports: Redshift

My Sales data for first two weeks of june, Monday Date i.e 1st Jun , 8th Jun are below
date | count
2015-06-01 03:25:53 | 1
2015-06-01 03:28:51 | 1
2015-06-01 03:49:16 | 1
2015-06-01 04:54:14 | 1
2015-06-01 08:46:15 | 1
2015-06-01 13:14:09 | 1
2015-06-01 16:20:13 | 5
2015-06-01 16:22:13 | 1
2015-06-01 16:27:07 | 1
2015-06-01 16:29:57 | 1
2015-06-01 19:16:45 | 1
2015-06-08 10:54:46 | 1
2015-06-08 15:12:10 | 1
2015-06-08 20:35:40 | 1
I need a find weekly avg of sales happened in a given range .
Complex Query:
(some_manipulation_part), ifact as
( select date, sales_count from final_result_set
) select date_part('h',date )) as h ,
date_part('dow',date )) as day_of_week ,
count(sales_count)
from final_result_set
group by h, dow.
Output :
h | day_of_week | count
3 | 1 | 3
4 | 1 | 1
8 | 1 | 1
10 | 1 | 1
13 | 1 | 1
15 | 1 | 1
16 | 1 | 8
19 | 1 | 1
20 | 1 | 1
If I try to apply avg on the above final result, It is not actually fetching correct answer!
(some_manipulation_part), ifact as
( select date, sales_count from final_result_set
) select date_part('h',date )) as h ,
date_part('dow',date )) as day_of_week ,
avg(sales_count)
from final_result_set
group by h, dow.
h | day_of_week | count
3 | 1 | 1
4 | 1 | 1
8 | 1 | 1
10 | 1 | 1
13 | 1 | 1
15 | 1 | 1
16 | 1 | 1
19 | 1 | 1
20 | 1 | 1
So I 've two mondays in the given range, it is not actually dividing by it. I am not even sure what is happening inside redshift.
To get "weekly averages" use date_trunc():
SELECT date_trunc('week', my_date_column) as week
, avg(sales_count) AS avg_sales
FROM final_result_set
GROUP BY 1;
I hope you are not actually using date as name for your date column. It's a reserved word in SQL and a basic type name, don't use it as identifier.
If you group by the day of week (DOW) you get averages per weekday. and sunday is 0. (Use ISODOW to get 7 for Sunday.)

A single query to count the number of distinct rows in one table and the highest value of a column from another table

I have two SQL tables. Table 1 is as follows:
SALEREF
1 | 40303020
2 | 40303021
3 | 40303021
4 | 40303021
5 | 41210028
6 | 4120302701
7 | 41210030
8 | 4112700803
9 | 4112700803
10 | 41215030
11 | 41215026
12 | 41215026
13 | 41215026
14 | 41215026
15 | 41215026
16 | 41215026
17 | 41215026
18 | 41215027
19 | 41215027
20 | 41215027
Table 2 ("LEDGER") is as follows:
SALESREF SALEDATE
0 | 4081200201 | 20140804
1 | 40303020 | 20141015
2 | 40303021 | 20141017
3 | 40303021 | 20141017
4 | 40303021 | 20141017
5 | 41210028 | 20121214
6 | 4120302701 | 20130926
7 | 41210030 | 20130926
8 | 4112700803 | 20131107
9 | 4112700803 | 20131107
10 | 41215030 | 20120720
What I am looking for is a single line that outputs the following:
TotalDistinctSalesRefsInTable1 HighestSaleDateValueInTable2 (that has a matching value in table 1)
9 20141017
the total number of distinct SALESREF's in table 1 and the latest SALESDATE value from table 2.
I've tried selecting within a query but quickly found the limitation of my knowledge although I know I can get the latest overall sale date by doing:
SELECT MAX(LEDGER.SALEDATE) AS LAST_DATE FROM LEDGER
I just need help piecing the whole thing together.
you can use left join , count and max to get your desired result
select count(distinct t1.salesref) as TotalDistinctSalesRefsInTable1,
ifnull(max(l.saledate),0) as HighestSaleDateValueInTable
from table1 t1
left join ledger l
on t1.salesref = l.salesref

Return Max(Recent_Date) for each month, Duplicate value and inner join issue - SQL

Basically, I want to achieve , for each months, like in this example, from January until March 2013, what is the Max(Most_Recent_Day) for each users.
Example, From January to March, every month in the Database, systems will capture the Most_Recent_Day for each users.
Below are the expected results:
User | Most_Recent_Day
--------------------------------
afolabi.banu | 1/31/2013
afolabi.banu | 2/7/2013
afolabi.banu | 3/21/2013
mario.sapiter | 1/22/2013
mario.sapiter | 2/7/2013
mario.sapiter | 3/11/2013
However, I want to have another DB column as well to be display .Below is the column.
User|Total_Hits | Recent_Month| Most_Recent_Day | Most_Recent_Days_Hits
I tried to use inner join, but the result are not what i expect. I got duplicated user name and duplicated recent day. Basically, I want only to display no duplicated record for the same user name.
Below is the result that I got. Please ignore the recent_month value since it's data from database.
User |Total_Hits | Recent_Month | Most_Recent_Day | Most_Recent_Days_Hits
-------------------------------------------------------------------------------------
afolabi.banu | 223 | 25 | 2/7/2013 | 5
afolabi.banu | 223 | 25 | 2/7/2013 | 5
afolabi.banu | 211 | 13 | 1/31/2013 | 3
afolabi.banu | 223 | 25 | 2/7/2013 | 5
afolabi.banu | 296 | 31 | 3/21/2013 | 1
afolabi.banu | 296 | 31 | 3/21/2013 | 1
mario.sapiter | 95 | 7 | 2/7/2013 | 5
mario.sapiter | 7 | 7 | 3/21/2013 | 1
mario.sapiter | 7 | 37 | 3/22/2013 | 1
mario.sapiter | 249 | 37 | 2/7/2013 | 5
This is my SQL Code
SELECT t.[User],
t.Total_Hits,
t.Recent_Month,
t.Most_Recent_Day,
t.Most_Recent_Day_Hits FROM UserUsageMonthly t
INNER JOIN
(
select
[User]
, max(Most_Recent_Day) as Most_Recent_Day
from UserUsageMonthly (NoLock)
where Application_Name='Daily Production Review' and Site_Collection='wrm13'
and Most_Recent_Day between '1/1/2013' and '3/31/2013'
group by [User], datepart(month,Most_Recent_Day)
) table2
ON
t.[User]=table2.[User]
AND t.Most_Recent_Day = table2.Most_Recent_Day
order by t.[User]
You should add the month value to your SQL SELECT
SELECT
MONTH(t.Most_Recent_Day) as 'MyMonth',
t.[User],
t.Total_Hits,
t.Recent_Month,
t.Most_Recent_Day,
t.Most_Recent_Day_Hits FROM UserUsageMonthly t
Then you can group by the month column
GROUP BY MyMonth

How to insert additional values in between a GROUP BY

i am currently making a monthly report using MySQL. I have a table named "monthly" that looks something like this:
id | date | amount
10 | 2009-12-01 22:10:08 | 7
9 | 2009-11-01 22:10:08 | 78
8 | 2009-10-01 23:10:08 | 5
7 | 2009-07-01 21:10:08 | 54
6 | 2009-03-01 04:10:08 | 3
5 | 2009-02-01 09:10:08 | 456
4 | 2009-02-01 14:10:08 | 4
3 | 2009-01-01 20:10:08 | 20
2 | 2009-01-01 13:10:15 | 10
1 | 2008-12-01 10:10:10 | 5
Then, when i make a monthly report (which is based by per month of per year), i get something like this.
yearmonth | total
2008-12 | 5
2009-01 | 30
2009-02 | 460
2009-03 | 3
2009-07 | 54
2009-10 | 5
2009-11 | 78
2009-12 | 7
I used this query to achieved the result:
SELECT substring( date, 1, 7 ) AS yearmonth, sum( amount ) AS total
FROM monthly
GROUP BY substring( date, 1, 7 )
But I need something like this:
yearmonth | total
2008-01 | 0
2008-02 | 0
2008-03 | 0
2008-04 | 0
2008-05 | 0
2008-06 | 0
2008-07 | 0
2008-08 | 0
2008-09 | 0
2008-10 | 0
2008-11 | 0
2008-12 | 5
2009-01 | 30
2009-02 | 460
2009-03 | 3
2009-05 | 0
2009-06 | 0
2009-07 | 54
2009-08 | 0
2009-09 | 0
2009-10 | 5
2009-11 | 78
2009-12 | 7
Something that would display the zeroes for the month that doesnt have any value. Is it even possible to do that in a MySQL query?
You should generate a dummy rowsource and LEFT JOIN with it:
SELECT *
FROM (
SELECT 1 AS month
UNION ALL
SELECT 2
…
UNION ALL
SELECT 12
) months
CROSS JOIN
(
SELECT 2008 AS year
UNION ALL
SELECT 2009 AS year
) years
LEFT JOIN
mydata m
ON m.date >= CONCAT_WS('.', year, month, 1)
AND m.date < CONCAT_WS('.', year, month, 1) + INTERVAL 1 MONTH
GROUP BY
year, month
You can create these as tables on disk rather than generate them each time.
MySQL is the only system of the major four that does have allow an easy way to generate arbitrary resultsets.
Oracle, SQL Server and PostgreSQL do have those (CONNECT BY, recursive CTE's and generate_series, respectively)
Quassnoi is right, and I'll add a comment about how to recognize when you need something like this:
You want '2008-01' in your result, yet nothing in the source table has a date in January, 2008. Result sets have to come from the tables you query, so the obvious conclusion is that you need an additional table - one that contains each month you want as part of your result.