How query works with missing Group by values - sql

I am tryng to write a query to pull the total discount as well as revenue of my customer's orders by day. Note that for each ship_id there will be several items so I want to have the sum clauses as below and in the end, I have that group by and I want to group them by ship_id (this is unique for each order).
I got a result of 2M rows (this could be correct because we are a big) but I am not sure if my group by is correct. What if I only put ship_id there? How my query understands it?
d.ship_id
,to_char(d.order_datetime,'yyyy/mm/dd hh24:mi:ss') as datetime_order
,to_char(d.order_datetime, 'D') as day_order
,to_char(d.order_datetime, 'MM') as month_order
,sum(di.discount) as discount
,sum(di.price * di.units) AS price
FROM
table1 d
JOIN
table2 di
ON
d.ship_id = di.ship_id
GROUP BY
d.ship_id
,to_char(d.order_datetime,'yyyy/mm/dd hh24:mi:ss')
,to_char(d.order_datetime, 'D')
,to_char(d.order_datetime, 'MM')

In this query you grouping result by
ship_id (order)
d.order_datetime yyyy/mm/dd hh24:mi:ss (i think this is wrong if you need group only by day) this group is grouping by day,month,year,hour,minute and seconds
d.order_datetime 'D' (grouping by day correct)
d.order_datetime 'mm' (grouping by month correct, doesn't change results of grouping by day)
P.S.: I dont see grouping by costumer in anywhere.

Your query will sumarize all values groupped by itens on group by:
If you put, something like:
Select ship_id, ,sum(di.discount) as discount
,sum(di.price * di.units) AS price from table1 group by ship_id
The query will return Price and discount groupped by ship_id, when you make a group by you must put all non-*aggregate fields on group by.
*Aggregate funtions (Sum,AVG,count...)
Try explain better your problem to make me understand your situation(problem).

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)

Write a query to display the total month wise sales amount received in the past 1 year

Table StructureWrite a query to display the total month wise sales amount received in the past 1 year . Display details like sales month, total sales amount. Give an alias_name as MONTH for retrieved sales month, TURN_OVER for sales amount. Sort the result by amount in descending order.
(Hint: Use table Sales_info. Use to_char for retrieving the month. Net amount for sales amount calculation. Use sysdate for calculation of past 1 year sales. DATA IS CASE-SENSITIVE.)
The code I have written is fetching me all years sales data.
select to_char(Sales_Date,'Month')"MONTH"
Net_Amount as Turn_Over
from Sales_Info
where Sales_Date= add_months(Sysdate,-12)
select to_char(Sales_Date,'MON')"MONTH",
Net_Amount as TURN_OVER
from Sales_Info
where Sales_Date > add_months(Sysdate,-12)
order by Net_Amount desc;
I'm not going to do your homework for you, but here is a list of things currently missing from your query:
a comma in the SELECT list
you need greater than, not equals because you want all dates "more than the moment it was a year ago"
you need to break your data into groups where each group has the same month, and you need to sum up all the data in that month, so your query needs to have the words GROUP BY and SUM in it..
The code I have written is fetching me all years sales data
No, the query as it stands will be giving you only the sales that happened at exactly the current date-time, one year ago, which is probably 0 records
You are pretty close. What you are missing is the GROUP BY and summary functions:
select to_char(Sales_Date, 'Month') as "MONTH"
SUM(Net_Amount) as Turn_Over
from Sales_Info
where Sales_Date= add_months(Sysdate, -12)
group by to_char(Sales_Date, 'Month');
Note that there are still some significant issues with the query. For instance, I really am not a fan of using month names for what you are doing. It leaves out the year. In fact, the above query is going to combine data from the current month and the same month last year.
I would instead go for complete months. And use trunc() instead:
select trunc(Sales_Date, 'MON') as "MONTH"
SUM(Net_Amount) as Turn_Over
from Sales_Info
where Sales_Date = add_months(trunc(Sysdate, 'MON'), -12) and
Sales_Date < trunc(sysdate, 'MON')
group by to_char(Sales_Date, 'Month')
order by "MONTH".
In a real-world environment, this would typically provided cleaner, more useful results. In addition, because the first column is actually the date, it is easy to sort by.
The ans will be :
Select to_char(Sales_Date , 'MON' ) as "MONTH" , sum(Net_Amount) as TURN_OVER
from Sales_Info
where Sales_Date > add_months(Sysdate , -12)
group by to_char(Sales_Date , 'MON')
order by TURN_OVER desc;

SQL Query Help Finding Highest Order Value From Each Day

I have two tables, Customer and Order.
In the Order table, I have a column called date_time that stores the date and time of an order. I also have the CustomerID.
I want to get the customers ID for the orders with the highest value from that day.
This is the query to retrieve the order with the highest amount in each day:
SELECT
MAX(order_amount) AS "Highest Day Amount",
to_char(date_time, 'dd/mm/yyyy') AS "ORDER DATE"
FROM
orders
GROUP BY
to_char(date_time, 'dd/mm/yyyy');
I need to use to_char because the date_time column contains both the date and time (for example: 19/05/2021 17:50) and if I don't use the to_char because I have more than one order in each day, it will consider the date to be different, because of the time component, and it will list two orders on that day instead of 1 order with the highest total.
And then I want to fetch the customer id from those orders, however I'm not sure how to do that.
I want to get the customers ID for the orders with the highest value from that day.
You should not need to_char(), but how you truncate to the date depends on the database. The key idea is that you want to use a window function:
SELECT o.*
FROM (SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY to_char(date_time, 'YYYY-MM-DD') ORDER BY order_amount DESC) as seqnum
FROM orders o
) o
WHERE seqnum = 1;
This returns the entire row with the highest order amount. You can format the result set how you want.
In Oracle, you can do this with aggregation. I would recommend:
select trunc(date_time), max(order_amount),
max(customer_id) keep (dense_rank first order by order_amount desc) as customer_id
from orders o
group by trunc(date_time);
The keep syntax is Oracle's (rather verbose) way of implementing a "first" aggregation function.
You only need to add your customers IDcto the select and the group by
SELECT MAX(order_amount) as "Highest Day Amount", to_char(date_time, 'dd/mm/yyyy') AS "ORDER DATE", customerID
FROM orders GROUP BY to_char(date_time, 'dd/mm/yyyy'), customerID
If you want more details from customers, you will need to join this table to customers table

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.

Multiple Counts Over Multiple Dates

I am essentially doing the following query (edited):
Select count(orders)
From Orders_Table
Where Order_Open_Date<=##/##/####
and Order_Close_Date>=##/##/####
Where the ##/##/##### is the same date. So in essence the number of 'open' orders for any given day. However I am wanting this same count for every single day for a year and don't want to write a separate query for each day for the whole year. I'm sorry this is probably really simple but I am new to SQL and I guess I don't know how to search for an answer to this question since my searches have come up with nothing. Thanks for any help you can offer.
why not
select Order_Date, count(orders) from Orders_Table group by Order_Date
and for last year
select Order_Date, count(orders) from Orders_Table where Order_Date > DATE_SUB(CURDATE(), INTERVAL 1 YEAR) group by Order_Date;
SELECT CONVERT(VARCHAR, Order_Date, 110), count(orders)
FROM Orders_Table
WHERE Order_Date = BETWEEN #A AND #B
GROUP BY CONVERT(VARCHAR, Order_Date, 110)
If you want to have every day of the year, including those with no orders, you will need to generate a temporary table or similar containing every date in the range and left/right join it to the Orders_Table data. This depends upon which RDBMS you're using. In SQL Server I have done this using a user defined function which returns a table variable.