problem using Aggregate functions with joins - asp.net

I have two tables Say Table -A and table-B
Table-A having
Userid | Date
|
101 | 15 Aug ,2011
102 | 15 Aug ,2011
103 | 16 Aug ,2011
104 | 16 Aug ,2011
105 | 17 Aug ,2011
Table -B
Userid(f.k) | sts
101 | x
102 | y
101 | z
103 | x
101 | y
Required output is
Table-C
I want table c output as
DAte ,Total ,Sts as X,Sts as y, Avg of
Date | Total | Sts (if=x) |Sts (if=y) |Avg (Total/2)
15 Aug| 20 | 15 |5 |10
16aug | 30 | 22 |8 |15
I tried using :
select Date, select case when [Tasble-B].Sts='x' Then 0 else 1 END as StsX,select case when [Tasble-B].Sts='Y' Then 0 else 1 END as StsY,Total/2
from
Table-A
inner join Table-B on Table-A.UserID = Table-B.UserID
b group by RegDate
I am getting Error , I am Stuck with this query.Please Help
Thanks in advance

select Date,
select case when [Tasble-B].Sts='x' Then 0
else 1
END as StsX,
select case when [Tasble-B].Sts='Y' Then 0
else 1
END as StsY,
Total/2
from Table-A
inner join Table-B
on Table-A.UserID = Table-B.UserID
b group by RegDate
You do group by RegDate so I assume you should use RegDate in the field list instead of Date or perhaps RegDate as Date.
You are missing the total column. You could do that with count(*) as Total
Your select case ... statements should not be select's but sum(case ...)
Total/2, where does Total come from? My guess is that you want the average of StsX and StsY but it could also mean that you want to use the calculated Total column and divide that by 2. If that is the case you need to repeat your aggregate statement count(*)/2 or you could use this entire query as a sub-query and do the calculation using the field Total as you already do, Total/2.
Your table names need to be encapsulated in brackets [Table-B].
You have an extra b before the group by clause. You should remove that.
`

you can try:
select [Date],
(SUM(case when B.Sts='x' Then 1
else 0
END) +
SUM( case when B.Sts='Y' Then 1
else 0
END)) AS Total,
SUM( case when B.Sts='x' Then 1
else 0
END) AS StsX,
SUM( case when B.Sts='Y' Then 1
else 0
END) as StsY,
(SUM(case when B.Sts='x' Then 1
else 0
END) +
SUM( case when B.Sts='Y' Then 1
else 0
END))
/2.0 AS Average
from A
inner join B
on A.UserID = B.UserID
group by [Date]
I tested it with:
WITH A (UserId, [Date]) AS (
SELECT 101, '2011-08-15'
UNION
SELECT 102, '2011-08-15'
UNION
SELECT 103, '2011-08-16'
UNION
SELECT 104, '2011-08-16'
UNION
SELECT 105, '2011-08-17'
),
B (UserId, sts) AS
(
SELECT 101, 'x'
UNION
SELECT 102, 'y'
UNION
SELECT 101, 'z'
UNION
SELECT 103, 'x'
UNION
SELECT 101, 'y'
)
select [Date],
(SUM(case when B.Sts='x' Then 1
else 0
END) +
SUM( case when B.Sts='Y' Then 1
else 0
END)) AS Total,
SUM( case when B.Sts='x' Then 1
else 0
END) AS StsX,
SUM( case when B.Sts='Y' Then 1
else 0
END) as StsY,
(SUM(case when B.Sts='x' Then 1
else 0
END) +
SUM( case when B.Sts='Y' Then 1
else 0
END))
/2.0 AS Average
from A
inner join B
on A.UserID = B.UserID
group by [Date]

Related

SQLite: Group data within certain time interval

I have a single table which stores data of orders:
Orders Table:
id | order_time | quantity | ...
1 | 1592821854318 | 2
2 | 1592901538199 | 4
3 | 1592966454547 | 1
4 | 1593081282406 | 9
5 | 1593141826330 | 6
order_time table is UNIX timestamp.
Using below query I am able to get available data grouped by days (86400000 = 24 hours):
SELECT order_time+ (86400000 - (order_time % 86400000)) as gap, SUM(quantity) as
totalOrdersBetweenInterval
FROM USAGE_DETAILS ud
WHERE order_time >= 1590969600 AND order_time <= 1593388799000
GROUP BY gap
ORDER BY gap ASC
Suppose for this month of June, I receive order on 1, 4, 6, 7 date then by using above query I am able to retrieve data as follow :
gap | totalOrdersBetweenInterval
1 | 5
4 | 6
6 | 4
7 | 10
I would receive UNIX timestamp in gap column but for the sake of example I have used readable dates.
Above query will only retrieve data for the days which would have received order but I want to split data in range like below which also include days with no orders :
gap | totalOrdersBetweenInterval
1 | 5
2 | 0
3 | 0
4 | 6
5 | 0
6 | 4
7 | 10
8 | 0
9 | 0
. | .
. | .
How do I go about that?
You need a query that returns 30 rows:1,2,...,30 for the days of June.
You could do it with a recursive CTE:
with days as (
select 1 day
union all
select day + 1
from days
where day < 30
)
but I'm not sure if Android uses a version of SQLite that supports CTEs.
If it does support them, all you need to do is join the CTE with a LEFT join to your query:
with
days as (
select 1 day
union all
select day + 1
from days
where day < 30
),
yourquery as (
<your query here>
)
select d.day, coalesce(t.totalOrdersBetweenInterval, 0) totalOrdersBetweenInterval
from days d left join yourquery t
on t.gap = d.day
If Android does not support CTEs you will have to build the query that returns the days with UNION ALL:
select d.day, coalesce(t.totalOrdersBetweenInterval, 0) totalOrdersBetweenInterval
from (
select 1 day union all select 2 union all
select 3 union all select 4 union all
......................................
select 29 union all select 30
) d left join (
<your query here>
) t
on t.gap = d.day
Thanks to #forpas for helping me out.
Just posting in case someone is searching for slicing data by unix time intervals.
with
days as (
select 1590969600000 day --Starting of June 1 2020
union all
select day + 86400000 --equivalent to 1 day
from days
where day < 1593388799000 --Less than 28th of June
),
subquery as (
SELECT order_time+ (86400000 - (order_time % 86400000)) as gap, SUM(quantity) as
totalOrdersBetweenInterval
FROM USAGE_DETAILS ud
WHERE order_time >= 1590969600000 AND order_time <= 1593388799000
GROUP BY gap
)
select d.day, coalesce(t.totalOrdersBetweenInterval, 0) totalOrdersBetweenInterval
from days d left join subquery t
on t.gap = d.day
order by d.day

R: Create groups within column

I'm trying to group an age column into an age group column and summarize by that grouping.
ie I need the dataset below -
AGE
1
2
5
68
27
4
2
33
45
To become
AGE_GRP COUNT
1-10 5
11-20 0
21-30 1
31-40 1
40+ 2
I'm using R
Thanks.
You need CASE statement to split the AGE into different groups
SELECT CASE
WHEN AGE BETWEEN 1 AND 10 THEN '1-10'
WHEN AGE BETWEEN 11 AND 20 THEN '11-20'
WHEN AGE BETWEEN 21 AND 30 THEN '21-30'
WHEN AGE BETWEEN 31 AND 40 THEN '31-40'
ELSE '40+'
END AS AGE_GRP,
Count(1) as Cnt
FROM yourtable
GROUP BY CASE
WHEN AGE BETWEEN 1 AND 10 THEN '1-10'
WHEN AGE BETWEEN 11 AND 20 THEN '11-20'
WHEN AGE BETWEEN 21 AND 30 THEN '21-30'
WHEN AGE BETWEEN 31 AND 40 THEN '31-40'
ELSE '40+'
END
If you don't want to repeat the CASE statement in GROUP BY then use this
SELECT AGE_GRP,
Count(1) AS cnt
FROM (SELECT CASE
WHEN AGE BETWEEN 1 AND 10 THEN '1-10'
WHEN AGE BETWEEN 1 AND 10 THEN '11-20'
WHEN AGE BETWEEN 1 AND 10 THEN '21-30 '
WHEN AGE BETWEEN 1 AND 10 THEN '31-40'
ELSE '40+'
END AS AGE_GRP
FROM yourtable) A
GROUP BY AGE_GRP
You have zero values so you need a left join:
select agegrp, count(t.agegrp)
from (select '1-10' as agegrp, 1 as lowb, 10 as hib union all
select '11-20' as agegrp, 11, 20 union all
select '21-30' as agegrp, 21, 30 upperbound union all
select '31-40' as agegrp, 31, 40 as upperbound union all
select '40+' as agegrp, 41, NULL as upperbound
) ag left join
t
on t.age >= ag.lowb and t.age <= ag.hib
group by ag.agegrp
order by ag.lowb;
Note: this assumes the column is an integer, so a value like 30.5 isn't allowed. It is easy to adjust the query to handle non-integer ages, if that is the requirement.

Build a SQL with sum

Here is my table - PK is (Con_num, version, order) :
Con_num version operation amount
15 1 A 1
15 1 B 2
15 1 C 3
15 2 A 4
15 3 A 5
15 3 B 6
15 4 C 7
Con_num is the contract number.
version is the version number.
operation is just an ID for an operation.
amount is the amount of the operation.
I would like to have the total amount per version. The tricky part is that: for version 1, i just have to sum the amount. But for version 2, I need to sum the version 2 line (with operation = A) and to take the two lines from version 1 (with operation != A). Therefore, for version 3, i will take the two lines of version 3, and only the line with operation = C from version 1. Any new operation invalidate the one from the previous versions.
The result will be:
Con_num version amount
15 1 6 (1 + 2 + 3)
15 2 9 (4 + 2 + 3)
15 3 14 (5 + 6 + 3)
15 4 18 (5 + 6 + 7)
How can I do that ?
For each con_num and version add up all records
for the same con_num
with no version greater than the version in question
having the highest version per operation
To get the amount of the record with the highest version can be solved with Oracle's KEEP FIRST/LAST:
select
base.con_num,
base.version,
(
select sum(max(mytable.amount) keep (dense_rank last order by mytable.version))
from mytable
where mytable.con_num = base.con_num
and mytable.version <= base.version
group by mytable.con_num, mytable.operation
) as total
from (select distinct con_num, version from mytable) base;
select
Con_num, version, orderno, a0+a1+a2 as amount
from (
select
Con_num, version, orderno
, lag(amount,2) over(partition by Con_num order by version, orderno) a2
, lag(amount,1) over(partition by Con_num order by version, orderno) a1
, amount a0
, row_number() over(partition by Con_num, version order by orderno desc) as rn
from table1
) d
where rn = 1
You seem to want only the "most recent" combinations of (Con_num, version, orderno) which can be identified using row_number() and the values required established using lag(,1) and lag(,2) but I don't reach the stated result.
result:
| con_num | version | orderno | amount |
|---------|---------|---------|--------|
| 15 | 1 | 3 | 37 |
| 15 | 2 | 1 | 42 |
| 15 | 3 | 2 | 35 |
sqlfiddle example
Using LAST_VALUE analytic function.
select con_num, version, q1+q2+q3
from (
select x.*,
last_value(case when operation = 1 then amount end) ignore nulls over (order by version) q1,
last_value(case when operation = 2 then amount end) ignore nulls over (order by version) q2,
last_value(case when operation = 3 then amount end) ignore nulls over (order by version) q3
from x
)
group by con_num,version, q1, q2, q3
order by con_num,version;

SQL Count Data 1/2 hourly

I have a stored procedure that counts data for each hour,
Declare #DateTimeToFilter DATETIME;
--set #DateTimeToFilter = GetDate();
set #DateTimeToFilter = '6/5/14'
SET NOCOUNT ON;
WITH H ([Hour]) AS
( SELECT 7 UNION
SELECT 8 UNION
SELECT 9 UNION
SELECT 10 UNION
SELECT 11 UNION
SELECT 12 UNION
SELECT 13 UNION
SELECT 14 UNION
SELECT 15 UNION
SELECT 16 UNION
SELECT 17 UNION
SELECT 18 UNION
SELECT 19
)
SELECT H.[Hour],
COUNT(T.BookingID) AS NoOfUsers
FROM H
LEFT JOIN tbl_Visitor T
ON H.[Hour] = DATEPART(HOUR, T.TimeofArrival) AND
((DATEDIFF(dd, T.TimeofArrival, #DateTimeToFilter) = 0) AND (DATEDIFF(mm, T.TimeofArrival, #DateTimeToFilter) = 0) AND
(DATEDIFF(yy, T.TimeofArrival, #DateTimeToFilter) = 0))
GROUP BY H.[Hour];
This forces the data returned for each hour irrespective of whether there is any data or not.
How could I add the half hourly data to be added also, so the returned data look like.
Hour Count
7 0
7.5 0
8 0
8.5 0
9 0
9.5 0
10 4
10.5 0
11 0
11.5 0
12 0
12.5 0
13 0
13.5 0
14 5
14.5 0
15 2
15.5 0
16 2
16.5 0
17 0
17.5 0
18 0
18.5 0
19 0
19.5 0
The data is stored in the database as a smalltimedate, i.e. 2014-06-05 14:00:00
Any help is appreciated.
You can use minutes instead of hours:
with h ([Minute]) as (
select 420 union all
select 450 union all
select 480 union all
select 510 union all
select 540 union all
...
Divide the minutes to get fractional hours:
select h.[Minute] / 60.0 as [Hour], ...
Calculate the start and stop time for the interval to filter the data:
... on T.TimeofArrival >= dateadd(minute, h.[Minute], #DateTimeToFilter) and
T.TimeofArrival < dateadd(minute, h.[Minute] + 30, #DateTimeToFilter)
Below is an example that groups by half-hour intervals and can easily be extended for other intervals. I suggest you avoid applying functions to columns in the WHERE clause as that prevents indexes on those columns from being used efficiently.
DECLARE
#DateTimeToFilter smalldatetime = '2014-06-05'
, #IntervalStartTime time = '07:00:00'
, #IntervalEndTime time = '20:00:00'
, #IntervalMinutes int = 30;
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
, t256 AS (SELECT 0 AS n FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d)
, t64k AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num FROM t256 AS a CROSS JOIN t256 AS b)
, intervals AS (SELECT DATEADD(minute, (num - 1) * #IntervalMinutes, #DateTimeToFilter) AS interval
FROM t64k
WHERE num <= 1440 / #IntervalMinutes)
SELECT
interval
, CAST(DATEDIFF(minute, #DateTimeToFilter, interval) / 60.0 AS decimal(3, 1)) AS Hour
, COUNT(T.BookingID) AS NoOfUsers
FROM intervals
LEFT JOIN dbo.tbl_Visitor T
ON T.TimeofArrival >= intervals.interval
AND T.TimeofArrival < DATEADD(minute, #IntervalMinutes, intervals.interval)
WHERE
interval >= DATEADD(minute, DATEDIFF(minute, '', #IntervalStartTime), #DateTimeToFilter)
AND interval < DATEADD(minute, DATEDIFF(minute, '', #IntervalEndTime), #DateTimeToFilter)
GROUP BY interval
ORDER BY Hour;

How To Group By Only Some Rows

I have some records.
ID Salary WillGroupBy Amount
----------------------------------------
6320 100 1 15
6320 150 1 20
6694 200 0 25
6694 300 0 30
7620 400 1 45
7620 500 1 50
How can I group by only which "WillGroupBy = 1" records?
(I will SUM Salary and Amount columns)
I want to get this result:
ID Salary WillGroupBy Amount
----------------------------------------
6320 250 1 35
6694 200 0 25
6694 300 0 30
7620 900 1 95
Can you help me please :( ?
Solution:
SELECT ID, SUM(Salary) Salary, WillGroupBy, SUM(Amount) Amount
FROM YourTable
where WILLGROUPBY = 0
union all
SELECT ID, SUM(Salary) Salary, WillGroupBy, SUM(Amount) Amount
FROM YourTable
where WILLGROUPBY = 1
group by ID, WillGroupBy
I used this solution via Erhan.
I would to know that how it could be in another way.
With MySQL you can do:
SELECT ID, SUM(Salary) Salary, WillGroupBy, SUM(Amount) Amount, #row := #row + 1
FROM YourTable
JOIN (SELECT #row := 0) v
GROUP BY ID, IF(WillGroupBy = 1, -1, #row)
DEMO

Resources