Microsoft access Query rolling total every 5 lines not using dates - sql

I am new to Microsoft access.
I need a query that will allow me to sum a rolling total for every 5 lines of data. So on the sixth day I need a line to drop off the total and the new line to be added.
Fields:
ID, Daily_SUM
The results should be
ID Daily sum Weekly Sum
1 12
2 41
3 46
4 125
5 120 344
6 42 374
7 41 374
8 57 385
9 207 467
10 215 562
11 187 707
12 -43 623
13 45 611
14 56 460
15 40 285
16 8 106
17 95 244
18 580 779
19 360 1083
20 337 1380

You can do this with a correlated subquery. The challenge is actually getting NULL values on the first few rows:
select t.id, t.daily,
(select iif(count(*) = 7, sum(t3.daily), NULL)
from (select top 7 t2.daily
from table t2
where t2.id <= t.id
order by t2.id desc
) t3
) as weekly
from table t;
EDIT:
If we assume that the ids are assigned sequentially with no gaps, then you can use an explicit join:
select t.id, t.daily,
iif(count(*) = 7, sum(t2.daily), NULL) as weekly
from table t inner join
table t2
on t2.id between t.id - 6 and t.id
group by t.id, t.daily;

Related

How to find a specific value in consecutive date

I need your help for a little issue.
I use MS ACCESS to work with a database and I need to resolve a query. My query asks:
Find the CUSTOMER_ID and TRANSC_ID where 2 consecutive value between 200 and 500 WITHIN the same transc_id.
I explain.
I have this table in this format:
CUSTOMER_ID TRANSC_ID VALUE VALUE_DATE
51 10 15 29-12-1999
51 10 20 15-07-2000
51 10 35 18-08-2000
51 10 250 30-08-2000
51 10 13 10-09-2000
51 10 450 15-09-2000
51 11 5 15-09-2000
51 11 23 30-09-2000
51 11 490 10-10-2000
51 11 300 12-10-2000
51 11 85 30-10-2000
51 11 98 01-01-2000
53 10 65 15-10-2000
53 10 14 29-12-2000
And I need just
51 11 490 10-10-2000
51 11 300 12-10-2000
because the two values is consecutive (and both of them is >250 and <500).
How can I make a query in MS ACCESS to obtain this result?
Thank you.
You can get the "next" and "previous" values using correlated subqueries, and then do the comparison:
select t.*
from t
where t.value between 200 and 500 and
( (select top 1 t2.value
from t as t2
where t2.CUSTOMER_ID = t.CUSTOMER_ID and t2.TRANSC_ID = t.TRANSC_ID and
t2.value_date > t.value_date
order by t2.value_date
) between 200 and 500 or
(select top 1 t2.value
from t as t2
where t2.CUSTOMER_ID = t.CUSTOMER_ID and t2.TRANSC_ID = t.TRANSC_ID and
t2.value_date < t.value_date
order by t2.value_date desc
) between 200 and 500
);

SQL Server Obtain Pairs of records

I am trying to obtain "pairs" of records and I just cant figure out.
Here is what I have:
Id TruckId LocationId MaterialMode
145223 1198 19 43
145224 1199 19 43
145225 1200 19 43
145226 1198 20 43
145227 1199 20 43
145228 1200 20 43
145229 1199 21 46
145230 1198 21 46
145231 1200 21 46
145232 1198 22 46
145233 1199 22 46
145234 1200 22 46
145235 1198 19 43
145236 1199 19 43
145237 1200 19 43
145238 1198 20 43
145239 1199 20 43
145240 1200 20 43
145241 1199 21 46
145242 1198 21 46
145243 1200 21 46
145244 1198 22 46
145245 1199 22 46
145246 1200 22 46
I need to get the following:
Id A Id B
145223 145226
145224 145227
145225 145228
145229 145233
145230 145232
145231 145234
145235 145238
145236 145239
145237 145240
145241 145245
145242 145244
145243 145246
Basically matching a TruckId between 2 locations under the same material mode
I have tried:
SELECT
Id AS IdA,
Lead(Id, 1, NULL) OVER(PARTITION BY TruckId, MaterialMode ORDER BY Date) AS IdB
FROM T
This produces:
Id A Id B
145223 145226
145224 145227
145225 145228
*145226 145235
*145227 145236
*145228 145237
145229 145233
145230 145232
145231 145234
*145232 145242
*145233 145241
*145234 145243
145235 145238
145236 145239
145237 145240
145241 145245
145242 145244
145243 145246
Records with the * I don't want them. If a pair is matched then that record should not be part of "another match"
I believe I understand your problem and below is a solution.
Explanation: I sorted the data rows into start and end points sets like in gap and islands problems and then joined a start id with end id for same material mode and truck.
; with separationSet as
(
select
*,
dense_rank()
over(
partition by materialmode,truckid
order by locationid asc
) as r
from T
)
, scoredSet as
(
select
*,
row_number()
over(
partition by materialmode,truckid,r
order by id
) as r2
from separationSet
)
, startToEndPairs as
(
select
S.id as StartId,
E.id as EndId
from scoredSet S
join scoredSet E
on S.r=1 and E.r=2
and S.r2=E.r2
and S.TruckId=E.TruckId
and S.materialmode=E.materialmode
)
select
*
from starttoEndPairs
order by StartId asc
See working demo

T-SQL Group by day date but i want show query full date

I want to show the date field can not group.
My Query:
SELECT DAY(T1.UI_CreateDate) AS DATEDAY, SUM(1) AS TOTALCOUNT
FROM mydb.dbo.LP_UseImpression T1 WHERE T1.UI_BR_BO_ID = 45
GROUP BY DAY(T1.UI_CreateDate)
Result:
DATEDAY TOTALCOUNT
----------- -----------
15 186
9 1
3 2
26 481
21 297
27 342
18 18
30 14
4 183
25 553
13 8
22 469
16 1
17 28
20 331
28 90
14 33
8 1
But i want to show the full date...
Example result:
DATEDAY TOTALCOUNT
----------- -----------
15/06/2015 186
9/06/2015 1
3/06/2015 2
26/06/2015 481
21/06/2015 297
27/06/2015 342
18/06/2015 18
30/06/2015 14
4/06/2015 183
25/06/2015 553
13/06/2015 8
22/06/2015 469
16/06/2015 1
17/06/2015 28
20/06/2015 331
28/06/2015 90
14/06/2015 33
8/06/2015 1
I want to see the results...
I could not get a kind of results...
How can I do?
Thanx!
How about just casting to date to remove any time component:
SELECT CAST(T1.UI_CreateDate as DATE) AS DATEDAY, COUNT(*) AS TOTALCOUNT
FROM mydb.dbo.LP_UseImpression T1
WHERE T1.UI_BR_BO_ID = 45
GROUP BY CAST(T1.UI_CreateDate as DATE)
ORDER BY DATEDAY;
SUM(1) for calculating the count does work. However, because SQL has the COUNT(*) function, it seems a bit awkward.
So you can group by DAY(T1.UI_CreateDate) or use full date for grouping. But these are different . As both these dates '2015-04-15' and '2015-12-15' result in same DAY value of 15.
Assuming you want to group on DAY rather than date please try the below version of query:
SELECT DISTINCT
T1.UI_CreateDate as DATEDAY,
count(1) over (PARTITION BY DAY(T1.UI_CreateDate) ) AS TOTALCOUNT
FROM mydb.dbo.LP_UseImpression T1 WHERE T1.UI_BR_BO_ID = 45
sql fiddle for demo: http://sqlfiddle.com/#!6/c3337/1

How to query for non-matching records

I would like to create a query that finds those members with no reviews.
Table 1 - items selected
member/audno
733 12
733 13
733 14
844 12
844 13
844 14
955 12
955 13
955 14
Table 2 - reviews
member/audno/reviewno
733 12 111
844 13 112
955 14 113
Create new query with results of members with items with no reviews:
member/audno
733 13
733 14
844 12
844 14
955 12
955 13
How can I do this?
Try this
SELECT *
FROM
items_selected I
WHERE
NOT EXISTS (
SELECT *
FROM
reviews R
WHERE
R.member = I.member AND R.audno = I.audno
)
Another, equivalent query is based on a left join
SELECT I.*
FROM
items_selected I
LEFT JOIN reviews R
ON I.member = R.member AND I.audno = R.audno
WHERE
R.member IS NULL
You might test both of them and look which one is more performant.

Exclude the specific kind of record

I am using SQL Server 2008 R2. I do have records as below in a table :
Id Sys Dia Type UniqueId
1 156 20 first 12345
2 157 20 first 12345
3 150 15 last 12345
4 160 17 Average 12345
5 150 15 additional 12345
6 157 35 last 891011
7 156 25 Average 891011
8 163 35 last 789521
9 145 25 Average 789521
10 156 20 first 963215
11 150 15 last 963215
12 160 17 Average 963215
13 156 20 first 456878
14 157 20 first 456878
15 150 15 last 456878
16 160 17 Average 456878
17 150 15 last 246977
18 160 17 Average 246977
19 150 15 additional 246977
Regarding this data, these records are kind of groups that have common UniqueId. The records can be of type "first, last, average and additional". Now, from these records I want to select "average" type of records only if they have "first" or "additional" kind of reading in group. Else I want to exclude them from selection..
The expected result is :
Id Sys Dia Type UniqueId
1 156 20 first 12345
2 157 20 first 12345
3 150 15 last 12345
4 160 17 Average 12345
5 150 15 additional 12345
6 157 35 last 891011
7 163 35 last 789521
8 156 20 first 963215
9 150 15 last 963215
10 160 17 Average 963215
11 156 20 first 456878
12 157 20 first 456878
13 150 15 last 456878
14 160 17 Average 456878
15 150 15 last 246977
16 160 17 Average 246977
17 150 15 additional 246977
In short, I don't want to select the record that have type="Average" and have only "last" type of record with same UniqueId. Any solution?
Using EXISTS operator along correlated sub-query:
SELECT * FROM dbo.Table1 t1
WHERE [Type] != 'Average'
OR EXISTS (SELECT * FROM Table1 t2
WHERE t1.UniqueId = t2.UniqueId
AND t1.[Type] = 'Average'
AND t2.[Type] IN ('first','additional'))
SQLFiddle DEMO
Try something like this:
SELECT * FROM MyTable WHERE [Type] <> 'Average'
UNION ALL
SELECT * FROM MyTable T WHERE [Type] = 'Average'
AND EXISTS (SELECT * FROM MyTable
WHERE [Type] IN ('first', 'additional')
AND UniqueId = T.UniqueId)
The first SELECT statement gets all records except the ones with Type = 'Average'. The second SELECT statement gets only the Type = 'Average' records that have at least one record with the same UniqueId, that is of type 'first' or 'additional'.