I want to delete all records with a particular id and category except the one with the max date in MS Access.
Edit:
This is how my Data looks like
id
category
date
1
1
24 June 2021
1
1
20 June 2021
1
2
25 June 2021
1
2
26 June 2021
2
1
24 June 2021
2
1
26 June 2021
And this is how i want my data to look like
id
category
date
1
1
24 June 2021
1
2
26 June 2021
2
1
26 June 2021
I have this SELECT statement to show me all records I want to keep:
Select
t1.*
From
table t1
inner join
(select max(date) as maxdate, id
from table
group by id) t2 on t1.id = t2.id
and t1.date = t2.maxdate
I can't figure out a Delete statement that works in Access.
You can use:
delete from t
where t.date < (select max(t2.date)
from t as t2
where t2.id = t.id and t2.category = t.category
);
Related
I try to calculate in SQL MTD cost of a table.
I have following table:
year
user
month
type
cost
blank
2021
a
1
type1
10
0
2021
a
2
type1
20
0
2021
a
3
type1
35
0
2022
a
1
type1
5
0
2022
a
2
type1
35
0
2021
b
1
type1
10
0
2021
b
2
type1
30
0
What I need to have is now the MTD cost as per year, user and type
year
user
month
type
cost
costMTD
blank
2021
a
1
type1
10
10
0
2021
a
2
type1
20
10
0
2021
a
3
type1
35
15
0
2022
a
1
type1
5
5
0
2022
a
2
type1
35
30
0
2021
b
1
type1
10
10
0
2021
b
2
type1
30
20
0
Can i do this with a query in SQL?
I tried like this but it doesn't work:
SELECT t1.year, t1.user, t1.month, t1.type, t1.cost,
iif(t1.month = '1', t1.cost, t1.cost- t2.cost) AS costMTD, 0 AS blank
FROM dbo.usercosts AS t1 INNER JOIN dbo.usercosts AS t2
ON t1.year = t2.year
AND t1.user= t2.user
AND t1.type= t2.type
AND t2.month = iif(t2.month = '1', '1', t1.month - 1)
You can use LAG to see the previous row's cost.
select
year, user, month, type, cost,
cost - coalesce(lag(cost) over(partition by user order by year, month), 0) as costmtd,
0 as blank
from dbo.usercosts as
order by user, year, month;
I have a table in snowflake which has the following format
Year
Month
Sales
2021
03
a
2021
03
b
2021
03
c
2021
04
b
2021
04
c
2021
04
d
2021
04
f
And I want to get the YTD count and the comma separated list of sales(ytd)
So the output will be like
Year
Month
Count
Sales
2021
03
3
a,b,c
2021
04
7
a,b,c,d,f
I can get the YTD count but can't seem to figure out a way to get the list of sales. Any help will be appreciated
I don’t have anywhere to test this at the moment but something like this should work:
WITH CTE1 AS (
SELECT DISTINCT YEAR, MONTH
FROM TABLE1
)
SELECT T1.YEAR, T1.MONTH,
COUNT(T2.SALES), LISTAGG(T2.SALES,’,’)
FROM CTE1 T1
INNER JOIN TABLE1 T2 ON T1.YEAR = T2.YEAR
AND T1.MONTH >= T2.MONTH
GROUP BY T1.YEAR, T1.MONTH
I have a database for rounds of golf. I want to see how many rounds each user has per month for the last year.
To do that I created this view last_12_months with this code
SELECT date_part('month'::text, dates.date) AS month,
date_part('year'::text, dates.date) AS year
FROM ( SELECT (generate_series((now() - '1 year'::interval), now(), '1 mon'::interval))::date AS date) dates;
month
year
1
2020
2
2020
and so on to ...
12
2020
The summary view for counting the rounds is very simple also rounds_count_by_users
user_id
month
year
count_all
1
1
2020
15
1
3
2020
12
1
5
2020
10
2
4
2020
7
2
8
2020
6
2
9
2020
3
Now for what I want, querying for each user with left outer join is quite simple with
select *
from last_12_months
left outer join rounds_count_by_users
on last_12_months.month = rounds_count_by_users.month
and last_12_months.year = rounds_count_by_users.year
and user_id = 1
Which gives me all the months even when the user has no played rounds. What I would like however is to be able to do this for every user and make a materialized view for easy querying. Is there a nice and easy way of doing this? To be clear this is the final table I want.
This query doesn't work at least, that much I know.
select *
from last_12_months
left outer join rounds_count_by_users
on last_12_months.month = rounds_count_by_users.month
and last_12_months.year = rounds_count_by_users.year
where user_id = 1
user_id
month
year
count_all
1
1
2020
15
1
2
2020
null
1
3
2020
12
1
4
2020
null
1
5
2020
10
1
6
2020
null
1
7
2020
null
1
8
2020
null
1
9
2020
null
1
10
2020
null
1
11
2020
null
1
12
2020
null
2
1
2020
null
2
2
2020
null
2
3
2020
null
2
4
2020
7
2
5
2020
null
2
6
2020
null
2
7
2020
null
2
8
2020
6
2
9
2020
3
2
10
2020
null
2
11
2020
null
2
12
2020
null
I made an SQL Fiddle for this (slightly different values but same schema)
PS: I know about table aliases and data modeling and that stuff. My question is strictly about how to achieve the final result.
This query:
select * from last_12_months
where (year = year(current_date) - 1 and month >= month(current_date))
or
(year = year(current_date) and month < month(current_date))
returns the rows of last_12_months for the last 12 months (not including the current month).
This query:
select distinct user_id from rounds_count_by_users
returns all the distinct user_ids (it would be better if these ids where stored in a users table).
You must CROSS join the above queries and then LEFT join rounds_count_by_users:
select u.user_id, m.month, m.year, r.count_all
from (
select * from last_12_months
where (year = year(current_date) - 1 and month >= month(current_date))
or
(year = year(current_date) and month < month(current_date))
) m cross join (select distinct user_id from rounds_count_by_users) u
left outer join rounds_count_by_users r
on m.month = r.month and m.year = r.year and u.user_id = r.user_id
order by u.user_id, m.month
See the demo.
So I managed it to do it this way after help in the comments.
This leaves me with exactly what I wanted.
with all_rows as (
select * from view_last_12_months inner join users on true
)
select id as user_id, all_rows.year, all_rows.month, count_all
from all_rows left outer join view_rounds_count_last_year last12
on last12.month = all_rows.month
and last12.year = all_rows.year
and all_rows.id = last12.user_id
item loc year month quantity startdate
XYZ A 2020 1 3 23-06-2020
ABC B 2020 2 218 24-06-2020
SDC C 2020 6 107 25-06-2020
QWE D 2020 7 144 25-06-2020
XYZ A 2019 12 89 23-06-2020
ABC B 2019 11 218 24-06-2020
SDC C 2020 5 117 25-06-2020
QWE D 2020 6 144 25-06-2020
if i consider the above table then my output should look like this:
item loc year month quantity startdate
XYZ A 2020 1 89 23-06-2020
ABC B 2020 2 3 24-06-2020
SDC C 2020 6 117 25-06-2020
QWE D 2020 7 144 25-06-2020
so u can see that only quantities values changed and that we are taking from previos months and rest columns values are as it is.
It looks like you want window function lag(). For your sample data, this would produce the desired results:
select *
from (
select
item,
loc,
year,
month,
lag(quantity) over(partition by item, loc order by year, month) quantity,
startdate
from mytable
) t
where quantity is not null
Consider query which works in Access database:
SELECT Table1.*, (SELECT TOP 1 quantity FROM Table1 AS Dupe
WHERE Dupe.item = Table1.item AND Dupe.loc = Table1.loc
AND DateSerial(Dupe.[Year],Dupe.[Month],1)<DateSerial(Table1.[Year],Table1.[Month],1)
ORDER BY DateSerial(Dupe.[Year],Dupe.[Month],1)) AS PrevQty
FROM Table1;
If you want to return 0 when there is a gap in month sequence, consider:
SELECT Table1.*, Nz((SELECT quantity FROM Table1 AS Dupe
WHERE Dupe.item = Table1.item AND Dupe.loc = Table1.loc
AND DateSerial(Dupe.[Year],Dupe.[Month],1)=DateAdd("m",-1,DateSerial(Table1.[Year],Table1.[Month],1))
ORDER BY DateSerial(Dupe.[Year],Dupe.[Month],1)),0) AS PrevQty
FROM Table1;
Or
SELECT Q1.*, Nz(Q2.quantity,0) AS PrevQty FROM (
SELECT Table1.*, DateSerial([Year],[Month],1) AS FD FROM Table1) AS Q1
LEFT JOIN (
SELECT Table1.*, DateAdd("m",+1,DateSerial([Year],[Month],1)) AS PD FROM Table1) AS Q2
ON Q1.FD=Q2.PD AND Q1.item=Q2.item and Q1.loc=Q2.loc;
This is my query:
SELECT STAFF.stf_first_name + '' + STAFF.stf_last_name As Name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date) As Month,
SUM(case when RES_HAB_DATA.reshabdata_duration > 0
then (RES_HAB_DATA.reshabdata_duration/15) else 0 end) As ServiceDeliveryTime,
MONTH(RES_HAB_DATA.reshabdata_data_date) As MonthNumber
FROM RES_HAB_DATA
JOIN RES_HAB ON RES_HAB_DATA.reshab_id = RES_HAB.reshab_id
JOIN STAFF ON RES_HAB_DATA.staff_id = STAFF.stf_id
WHERE RES_HAB.serv_id = 30
AND RES_HAB_DATA.reshabdata_data_date >= '1/1/2015'
GROUP BY STAFF.stf_last_name,
STAFF.stf_first_name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date),
MONTH(RES_HAB_DATA.reshabdata_data_date)
ORDER BY MonthNumber
Which produces result set as:
Name Month ServiceDeliveryTime MonthNumber
----------------------------------------------------------------------------
mb January 52 1
MikeCasey January 10 1
MikeCasey February 4 2
PrecisionCareSupport February 0 2
MikeCasey March 4 3
PrecisionCareSupport March 0 3
MikeCasey April 8 4
PrecisionCareSupport April 0 4
MikeCasey May 16 5
MikeCasey July 4 7
PrecisionCareSupport July 1 7
PrecisionCareSupport August 0 8
MikeCasey September 10 9
MikeCasey October 12 10
I am generating a chart and would like to generate series for that chart but the series should be formed in a way that each series label must have all the tick values(zero if missing respective month). In Simple words,I want resultset as:
Name Month ServiceDeliveryTime MonthNumber
----------------------------------------------------------------------------
mb January 52 1
mb February 0 2
mb March 0 3
mb April 0 4
- - 0 5
Upto December then series will continue for Client MikeCasey upto December and so on...for all the series Labels.If any of the tick is missing for that client there will be value zero for that month.
How Can I produce this result set ? I want some uniform solution because there can be number of such queries for different charts.
Mr Shaw, try this
;WITH
(SELECT STAFF.stf_first_name + '' + STAFF.stf_last_name As Name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date) As Month,
SUM(case when RES_HAB_DATA.reshabdata_duration > 0
then (RES_HAB_DATA.reshabdata_duration/15) else 0 end) As ServiceDeliveryTime,
MONTH(RES_HAB_DATA.reshabdata_data_date) As MonthNumber
FROM RES_HAB_DATA
JOIN RES_HAB ON RES_HAB_DATA.reshab_id = RES_HAB.reshab_id
JOIN STAFF ON RES_HAB_DATA.staff_id = STAFF.stf_id
WHERE RES_HAB.serv_id = 30
AND RES_HAB_DATA.reshabdata_data_date >= '1/1/2015'
GROUP BY STAFF.stf_last_name,
STAFF.stf_first_name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date),
MONTH(RES_HAB_DATA.reshabdata_data_date)
) AS mytable
SELECT
myTableName.Name
,mytableMonth.Month
,ISNULL(mytable.ServiceDeliveryTime,0)
,mutableMonth.MonthNumber
FROM
(SELECT DISTINCT Name from mytable) mytableName
CROSS JOIN (SELECT DISTINCT Month,MonthNumber FROM mytable) mytableMonth
LEFT INNER JOIN mytable ON mytableName.Name = mytable.Name AND mytableMonth.Month = mytable.Month AND mytableMonthNumber = mytable.MonthNumber
ORDER BY mytableName.Name, mytableMonth.MonthNumber
I have taken all distinct months and names from your data and done a cross join.
;WITH mytable(Name,Month,ServiceDeliveryTime,MonthNumber) AS
(
SELECT STAFF.stf_first_name + '' + STAFF.stf_last_name As Name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date) As Month,
SUM(case when RES_HAB_DATA.reshabdata_duration > 0
then (RES_HAB_DATA.reshabdata_duration/15) else 0 end) As ServiceDeliveryTime,
MONTH(RES_HAB_DATA.reshabdata_data_date) As MonthNumber
FROM RES_HAB_DATA
JOIN RES_HAB ON RES_HAB_DATA.reshab_id = RES_HAB.reshab_id
JOIN STAFF ON RES_HAB_DATA.staff_id = STAFF.stf_id
WHERE RES_HAB.serv_id = 30
AND RES_HAB_DATA.reshabdata_data_date >= '1/1/2015'
GROUP BY STAFF.stf_last_name,
STAFF.stf_first_name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date),
MONTH(RES_HAB_DATA.reshabdata_data_date)
)
SELECT
myTableName.Name
,mytableMonth.Month_Name
,ISNULL(mytable.ServiceDeliveryTime,0) as ServiceDeliveryTime
,mytableMonth.id
FROM
(SELECT DISTINCT Name from mytable) mytableName
CROSS JOIN (SELECT DISTINCT Month_Name,id FROM MyMonths) mytableMonth
LEFT JOIN mytable ON mytableName.Name = mytable.Name AND mytableMonth.Month_Name = mytable.Month AND mytable.MonthNumber = mytable.MonthNumber
ORDER BY mytableName.Name, mytableMonth.id
MyMonths table is already created table with id as MonthNumber and Month_Name as Month.
Cheers!