count group by conflict oracle sql - sql

For the following query, I got the result below
select date, count(sales)
from table
where date between to_date('2015-09-01','YYYY-MM-DD') and to_date('2015-12-31','YYYY-MM-DD')
group by date
Date Count(sales)
01-SEP-15 480
01-SEP-15 2
01-SEP-15 3
01-SEP-15 2
16-SEP-15 12
16-SEP-15 7
It should just give me two rows-> 01-SEP-15 and count(sales) as 487.
and 16-SEP-15 and count(sales) as 19
How do I get that?

In Oracle a date also contains a time part. Your SQL client hides that from you by not including that in the output. You need to trunc() the date column to set the time part to 00:00:00
select trunc(date), count(sales)
from table
where date between to_date('2015-09-01','YYYY-MM-DD') and to_date('2015-12-31','YYYY-MM-DD')
group by trunc(date)

The logic that you probably intend is more like:
select trunc(date), count(sales)
from table
where trunc(date) between date '2015-09-01' and date '2015-12-31'
group by trunc(date);
However, if you have an index on date but not trunc(date), this would more naturally be written for performance as:
select trunc(date), count(sales)
from table
where date >= date '2015-09-01' and
date < date '2016-01-01'
group by trunc(date);

Related

Getting sum of a column that needs a distinct value from other column

I have this table where I wanted to get the sum of the balance column but each item should have a unique value from the date column.
I'm trying to find all the rows in the balance column that are the same and have the same date, and then find the sum of the balance column.
sample data with unique dates:
balance
date
700
2021-07-03
700
2021-09-03
300
2021-09-04
500
2021-09-05
query used goes like:
select distinct a.balance, a.date from table a where a.date between (some date) and (some other date)
I have tried:
select sum(a.balance), a.date from table a where a.date between (some date) and (some other date) group by a.date
but the balance column shows the sum of all of the values in the column but shows distinct dates as shown below.
balance
date
893938
2021-07-03
858585
2021-09-03
728366
2021-09-04
665322
2021-09-05
I guess this is a job for a subquery. So let's take your problem step by step.
I'm trying to find all the rows in the balance column that are the same and have the same date,
This subquery gets you that, I believe. It give the same result as SELECT DISTINCT but it also counts the duplicated rows.
SELECT COUNT(*) num_same_rows, balance, date
FROM `table`
WHERE a.datum BETWEEN '2021-01-01' AND '2021-09-01'
GROUP BY date, balance
and then find the sum of the balance column.
Nest the subquery like this.
SELECT SUM(balance) summed_balance, date
FROM (
SELECT COUNT(*) num_same_rows, balance, date
FROM `table`
WHERE a.datum BETWEEN '2021-01-01' AND '2021-09-01'
GROUP BY date, balance
) subquery
GROUP BY date
If you only want to consider rows that actually have duplicates, change your subquery to
SELECT COUNT(*) num_same_rows, balance, date
FROM `table`
WHERE a.datum BETWEEN '2021-01-01' AND '2021-09-01'
GROUP BY date, balance
HAVING COUNT(*) >= 1
Be careful here, though. You didn't tell us what you want to do, only how you want to do it. The way you described your problem calls for discarding duplicated data before doing the sums. Is that right? Do you want to discard data?
2nd query you posted looks OK - sort of.
However, I think that it is the fact that date column contains not only date, but also time (as DATE datatype in Oracle does). Therefore, I'd say that it is trunc you need. Something like this:
SELECT TRUNC (a.datum) datum,
SUM (a.balance) sum_balance
FROM table_a a
WHERE a.datum BETWEEN DATE '2021-01-01' AND DATE '2021-09-01'
GROUP BY TRUNC (a.datum)

Return ID if sum of value is between two possible date ranges, and output which date range it came from?

I have a table that has a similar structure as this:
UserID
Amount
Date
123
50
01/01/2021
234
105
02/01/2021
123
60
01/15/2021
345
70
01/15/2021
456
110
12/31/2020
345
50
02/15/2020
I have two date ranges, 01/01/2021 - 01/31/2021 and 02/01/2021 - 02/28/2021. I want to get a list of UserIDs if they had total amount >= 100 within these date ranges, and to specify which date range it came from.
So in this example, I'd like an output like this:
UserID
Total Amount
Date Range
123
110
January
234
105
February
User ID 345 and 456 would not be included since their total amounts only reached >= 100 outside of the date ranges.
In my code, I'm not sure how to exclude UserID 345 since technically they have an amount >= 100 coming from dates in both ranges and not just one single range.
I'm having troubles with only summing if it's within the date range and I'm not sure how to specify from which date range it's coming from:
SELECT
UserID
,SUM(amount)
FROM table
WHERE
date BETWEEN '01-01-2021' AND '01-31-2021' OR
date BETWEEN '02-01-2021' AND '02-28-2021'
GROUP BY
UserID
HAVING SUM(amount) >= 100
You could use CROSS APPLY to calculate the date range, and then group by it.
But in this instance, it appears you are just using whole months, so we can just use DATENAME.
Side notes:
You should not use mm-dd-yyyy format for date literals
You can combine your two periods together in this instance, I have not done so to leave you the option of disjoint periods.
SELECT t.UserID,
SUM(t.amount),
Month = DATENAME(month, t.date)
FROM table t
WHERE t.Date BETWEEN '2021-01-01' AND '2021-01-31' OR
t.date BETWEEN '2021-02-01' AND '2021-02-28'
GROUP BY UserId, DATENAME(month, t.date);
NOTE: if your dates are actually datetime values then your filter is wrong. Instead you must use a half open interval:
WHERE t.Date >= '2021-01-01' AND t.Date < '2021-02-01' OR
t.date >= '2021-02-01' AND t.Date < '2021-03-01'
If your date ranges are months, you can join to the ranges and then aggregate by user:
select min(range_name), user_name, sum(amount)
from t join
(values ('2021-01-01', '2021-01-31', 'January'),
('2021-02-01', '2021-02-28', 'February')
) v(range_start, range_end, range_name)
on t.date >= v.range_start and t.date <= v.range_end
group by userid
having count(distinct range_name) = 1 and
sum(amount) > 100;
The having clause limits the results both by the number of ranges and by the amount.
If you just wants months between particular dates, I would simplify this to:
select datepart(month, min(date)), userid, sum(amount)
from t
where date >= '2021-01-01' and date < '2021-03-01'
group by userid
having count(distinct month(date)) = 1 and
sum(amount) > 100;

SQL Server aggregation the latest 12 months

Suppose I have the following table:
Id Visitors Date
------------------------------
1 100 '2017-01-01'
2 200 '2017-01-02'
3 150 '2017-01-03'
I want a query to provide the average of a range of records for the last 12 months.
For one record I know that it would be like :
select avg(Visitors), Date
from Visitors_table
where Date between '2018-01-01' and '2017-01-01'
However, I need to do that for a range of dates and multiple records.
I know that Union will solve it, but if the range is one year for example It is not optimized to use 365 union
Get the dates from 1 year ago to current date:
SELECT
Date,
AVG(Visitors) AS avgvisitors,
FROM Visitors_table
WHERE Date > dateadd(year, -1, getdate())
GROUP BY Date
ORDER BY Date;
Since you need to group by date.

How can I pivot my T-SQL query output to get this specific table?

I am running a T-SQL query on SQL Server 2014. The query and its output are given below:
Use MyDatabase
SELECT
ID,
ArrivalMonth,
DateOfBirth
FROM [View1]
WHERE [ArrivalMonth] between '2017-01-01' and '2018-05-01'
The output of the above query looks like this (extract):
ID ArrivalMonth DateOfBirth
101 2017-01-01 1974-05-30
105 2017-05-01 1967-03-05
125 2017-05-01 NULL
... ... ...
I need a T-SQL query to give me the following output (based on the output above):
ArrivalMonth Number_Of_Bookings Number_Of_DOB_Captured
2017-01-01 130 110
2017-02-01 90 85
... ... ...
2018-05-01 115 70
The first column is the ArrivalMonth. Number_Of_Bookings is the count of number of records from the above query. Number_Of_DOB_Captured is the count of DateOfBirth which is NOT NULL.
I think may be the Pivot query might be the solution but I am confused as to how to execute it in this scenario.
You may left join a calendar table containing all the months to your current table, and then aggregate:
WITH months AS (
SELECT '2017-01-01' AS month UNION ALL
SELECT '2017-02-01' UNION ALL
...
SELECT '2017-12-01'
)
SELECT
m.month,
COUNT(*) AS Number_Of_Bookings,
COUNT(v.DateOfBirth) AS Number_Of_DOB_Captured
FROM months m
LEFT JOIN [View1] v
ON m.month = v.ArrivalMonth
WHERE
v.ArrivalMonth BETWEEN '2017-01-01' AND '2018-05-01'
GROUP BY
m.month;
The calendar table may be necessary here if it could be possible that, for some reason, a given arrival month have no data associated with it in your view. If you are certain that the view would always contain data for every month, then you may aggregate directly on your table without joining.
you can use count(Number_Of_Bookings), count(DateOfBirth) and group by ArrivalMonth
So you count the number of non null values for each different ArrivalMonth.
the query :
Select ArrivalMonth
, count(Number_Of_Bookings)
, count(DateOfBirth)
FROM [View1]
WHERE [ArrivalMonth] between '2017-01-01' and '2018-05-01'
group by ArrivalMonth

Oracle group orders by date and sum the total

My Orders table looks like:
order_id (number)
order_total (number)
created_date (timestamp)
status (varchar2)
My goal is to get a set of rows where each row represents all orders on that date, so I'm trying to group the orders by date and get the sum of the order_total. I'm also limiting the results by only selecting orders from the last 30 days.
To clarify, for example if there were 30 orders in the last 30 days all on unique days then I would get 30 rows in the result. Another example: if there were 10 orders on 30th July, and only 1 order on 31st July then I'm aiming to get 2 rows in the result set, with order_total summed for all 10 orders in the first row, and the second row would of course have the order_total of the single order on the 31st.
My attempt so far:
select
sum(order_total) total_amount,
to_char(created_date, 'DD/MM/YYYY') grouped_date
from
orders
where
status = 'Complete' and
created_date >= (sysdate-30)
group by
to_char(created_date, 'DD'), to_char(created_date, 'MM'), to_char(created_date, 'YYYY')
order by
created_date asc
This gives an error:
ORA-00936: missing expression
I have tried to use the solution from this question but I don't think it quite fits for my scenario (this is where my group by expression has come from).
Assuming order_id should not be there, and that created_date has a time component (which seems likely as it's a timestamp), you need to truncate the date to remove the time when doing the aggregation:
select
sum(order_total) as total_amount,
to_char(trunc(created_date), 'DD/MM/YYYY') as grouped_date
from
orders
where
status = 'Complete' and
created_date >= trunc(sysdate-30)
group by
trunc(created_date)
order by
trunc(created_date) asc
I've also applied trunc to the where clause, otherwise it would ignore any orders 30 days ago between midnight and whatever time you ran the query today. And I've used the trunc'd date directly in the order by, rather than the column alias, so that the order is right when you go across a month-end - ordering by the DD/MM/YYYY string value would put 01/07/2013 before 30/06/2013, for example.
Quick SQL Fiddle.