I need a desired output as below out of two input tables
order tableusers table
id order_date id username
1 2019-01-01 1 A
2 2019-01-01 2 B
3 2019-01-02 3 B
4 2019-01-03 4 A
5 2019-01-03 5 B
Desired Output
order_date username orders
2019-01-01 A 1
2019-01-02 A 0
2019-01-03 A 1
I tried with this query,
SELECT o. order_date as order_date, u.username as username,
ISNULL (COUNT (username),0) AS orders
FROM Order O LEFT JOIN users U ON o.id=u.id
WHERE u.username = ‘A’
GROUP BY o. order_date, u.username
ORDER BY o. order_date, u.username
Which give me this result
order_date username orders
2019-01-01 A 1
2019-01-03 A 1
I don't know how to bring this part in the result "2019-01-02 A 0"
could anyone please help me with the query, Thanks in advance
You can do:
select d.order_date, 'A' as username, coalesce(cnt, 0) as orders
from (select distinct order_date as order_date from orders) d
left join (
select o.order_date, count(*) as cnt
from orders o
join users u on u.id = o.id
where u.username = 'A'
group by o.order_date
) t on t.order_date = d.order_date
order by d.order_date
Result:
order_date username orders
----------- --------- ------
2019-01-01 A 1
2019-01-02 A 0
2019-01-03 A 1
See running example at db<>fiddle.
You can use the query below in which includeAllUsers (using CROSS JOIN) allows you to include 'A' --without put it in the SELECT clause--, and StrictMatching gives you the real dataset using matching ID between the two tables Order & Users (by the way, I really recommend you to change the name of your order table in Orders or other words, because ORDER is a reserved word).
select includeAllUsers.Order_Date,
coalesce(StrictMatching.username,includeAllUsers.username) User_Name,
count(distinct StrictMatching.username) Total_Orders
from (select o.order_date, u.username, u.id from orders o cross join users u) includeAllUsers
left join (select o.order_date, u.username,o.id from orders o join users u on o.id=u.id) StrictMatching
on includeAllUsers.order_date = StrictMatching.order_date and StrictMatching.username='A'
where includeAllUsers.username='A'
group by
includeAllUsers.order_date, StrictMatching.username, includeAllUsers.username;
By combining includeAllUsers and StrictMatching and filtering by StrictMatching.username='A' (in the criterium of the JOIN clause) et again by includeAllUsers.username='A' (in WHERE clause), you get the correct result.
Here is a link to verify
Related
I have this tables with example data:
Calendar
ID | Date
---+-----------
1 | 2020-01-01
2 | 2020-01-02
3 | 2020-01-03
EmployeeTimeWorked
ID | Date | HoursWorked | UserID
---+------------+--------------+-------
1 | 2020-01-01 | 2 | 2
2 | 2020-01-01 | 4 | 2
I want to make a MS-SQL query that shows days the user have not worked, and how many hours they have left to work (they should work 8 hours per day). All within within a time period, say a week.
The result should look like this:
EmployeeHaveNotWorked
Date | HoursLeftToWork
-----------+----------------
2020-01-01 | 2
Any idea how to make such a MS-SQL Query?
First get all users with all dates. This is done with a cross join. Seeing that you are using a UserID I suppose there is a users table. Otherwise get the users from the EmployeeTimeWorked table.
Then outer join the working times per user and date. This is a simple aggregation query.
Then subtract the worked hours from the required 8 hours.
select
u.userid,
c.date,
8 - coalesce(w.hours_worked, 0) as hours_left_to_work
from users u
cross join calendar c
left outer join
(
select userid, date, sum(hoursworked) as hours_worked
from employeetimeworked
group by userid, date
) w on w.userid = u.userid and w.date = c.date
order by u.userid, c.date;
Use a cross join to generate all possible rows and then filter out the ones that exist:
select u.userid, c.date,
8 - coalesce(sum(HoursWorked), 0) as remaining_time
from calendar c cross join
(select distinct userid from EmployeeTimeWorked) u left join
EmployeeTimeWorked etw
on etw.userid = u.userid and etw.date = c.date
where etw.userid is null
group by u.userid, c.date
having sum(HoursWorked) < 8
This query seem to have done it for me:
select * from (select c.Date, 8 - coalesce(sum(t.durationHours),0) hours_left_to_work
from Calendar c
left join TimeLog t on t.Date = c.Date
where c.date >= '2020-08-01' and c.date <= '2020-08-31'
group by c.Date) as q1
where q1.hours_left_to_work IS NOT NULL
AND q1.hours_left_to_work > 0;
TimeLog = EmployeeTimeWorked
I have two tables, info and transactions.
info looks like this:
customer ID Postcode
1 ABC 123
2 DEF 456
and transactions looks like this:
customer ID day frequency
1 1/1/12 3
1 3/5/12 4
2 4/6/12 2
3 9/9/12 1
I want to know which day has the highest frequency for each postcode.
I know how to reference from two different tables but im not too sure how to reference multiple columns based on their values to other columns.
The output should be something like this:
customer ID postcode day frequency
1 ABC 123 3/5/12 4
2 DEF 456 4/6/12 2
3 GHI 789 9/9/12 1
and so on.
You can filter with a correlated subquery:
select
i.*,
t.day,
t.frequency
from info i
inner join transactions t on t.customerID = i.customerID
where t.frequency = (
select max(t.frequency)
from info i1
inner join transactions t1 on t1.customerID = i1.customerID
where i1.postcode = i.postcode
)
Or, if your RBDMS supports window functions, you can use rank():
select *
from (
select
i.*,
t.day,
t.frequency,
rank() over(partition by i.postcode order by t.frequency desc)
from info i
inner join transactions t on t.customerID = i.customerID
) t
where rn = 1
I have tables:
tbl-city
id city
---------
1 A
2 B
3 C
tbl-orders
ord_id product_id city date
----------------------------------
1 1 1 12/3/18
2 1 2 13/3/18
3 2 3 12/4/18
4 1 3 14/4/18
5 3 2 11/2/18
6 1 1 15/1/18
7 2 3 15/4/28
I need to get all latest order Id from table orders
by city wise and product wise using date
Like this:
ord_id product_id city
---------------------------
1 1 1
2 1 2
7 2 3
5 3 2
How can I get this?
JOIN/INNER JOIN or any other way?
You can use correlated subquery :
select o.*
from orders o
where date = (select max(o1.date)
from orders o1
where o1.product_id = o.product_id and o1.city = o.city
);
If ord_id increases along with the date (as would be typical), then a simple aggregation works.
select product_id, city, max(ord_id)
from tbl_ord
group by product_id, city;
Otherwise, the typical method would use row_number():
select o.*
from (select o.*,
row_number() over (partition by product_id, city order by date desc) as seqnum
from tbl_ord o
) o
where seqnum = 1;
In older versions of MySQL, a correlated subquery is a good route. But if you want exactly one row per product and city, use ord_id:
select o.*
from tbl_ord o
where o.ord_id = (select o2.ord_id
from tbl_ord o2
where o2.product_id = o.product_id and o2.city = o.city
order by o2.date desc
limit 1
);
i have 1 table inventory_movement here is data in table
product_id | staff_name | status | sum | reference_number
--------------------------------------------------
1 zes cp 1 000122
2 shan cp 4 000133
i have another table inventory_orderproduct where i have cost date
orderdate product_id cost
--------------------------------
01/11/2018 1 3200
01/11/2018 2 100
02/11/2018 1 4000
02/11/2018 1 500
03/11/2018 2 2000
i want this result
product_id| staff_name | status | sum reference_number | cost
--------------------------------------------------------------
1 zes cp 1 000122 4000
2 shan cp 4 000133 2000
here is my query
select ipm.product_id,
case when ipm.order_by_id is not null then
(select au.first_name from users_staffuser us inner join auth_user au on us.user_id= au.id
where us.id = ipm.order_by_id) else '0' end as "Staff_name"
,ipm.status,
Sum(ipm.quantity), ip.reference_number
from inventory_productmovement ipm
inner join inventory_product ip on ipm.product_id = ip.id
inner join users_staffuser us on ip.branch_id = us.branch_id
inner join auth_user au on us.user_id = au.id
AND ipm.status = 'CP'
group by ipm.product_id, au.first_name, ipm.status,
ip.reference_number, ip.product_name
order by 1
Here is the solution of your question.its working fine.if you like the answer please vote!
SELECT i.product_id,i.staff_name,i.status,i.sum reference_number ,s.Cost
FROM (SELECT product_id,MAX(cost) AS Cost
FROM inventory_orderproduct
GROUP BY product_id ) s
JOIN inventory_movement i ON i.product_id =s.product_id
In the given situation, this should work fine:
Select table1.product_id, table2.staff_name, table2.status, table2.reference_number,
MAX(table1.cost)
FROM table2
LEFT JOIN table1 ON table1.product_id = table2.product_id
GROUP BY table2.product_id, table2.staff_name, table2.status, table2.reference_number
You can use the below query to get MAX cost for products
SELECT i.product_id,i.staff_name,i.status,i.sum reference_number ,s.MAXCost
FROM (SELECT product_id,MAX(cost) AS MAXCost
FROM inventory_orderproduct
GROUP BY product_id ) s
JOIN inventory_movement i ON i.product_id =s.product_id
For Retrieving the cost using the latest date use the below query
WITH cte as (
SELECT product_id,cost
,ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY orderdate DESC) AS Rno
FROM inventory_orderproduct )
SELECT i.product_id,i.staff_name,i.status,i.sum reference_number ,s.Cost
FROM cte s
JOIN inventory_movement i ON i.product_id =s.product_id
WHERE s.Rno=1
You can use below query it will pick the data according to the latest date
WITH result as (
SELECT product_id,cost
,ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY date DESC)
FROM inventory_orderproduct )
SELECT i.product_id,i.staff_name,i.status,i.sum reference_number ,s.Cost
FROM result s
JOIN inventory_movement i ON i.product_id =s.product_id
I have three tables, customers, orders and customers-orders like this:
Customers:
ID NAME
1 Peter
2 Jack
3 Lisa
Orders:
ID INIT_DATE END_DATE
1 10-11-2014 10-11-2015
2 23-11-2014 01-01-2015
3 23-11-2014 03-05-2015
4 04-04-2016 08-11-2016
5 13-07-2016 01-11-2016
6 04-06-2016 30-10-2016
7 12-11-2014 01-05-2015
8 26-11-2014 10-10-2015
9 05-09-2016 11-11-2016
Customers_Orders:
CUSTOMER_ID ORDER_ID
1 1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
3 9
I need to get customers who have all orders outdated. I mean, those orders which sysdate is not between init_date and end_date. In this case, the expected result is 1-Peter.
What i tried is this:
SELECT *
FROM Customers
WHERE
ID NOT IN (
SELECT DISTINCT Customers_Orders.CUSTOMER_ID
FROM Customers_Orders, Orders
WHERE Customers_Orders.ORDER_ID = Orders.ID
AND Orders.INIT_DATE <= SYSDATE AND Orders.END_DATE > SYSDATE
)
But i don't like the "NOT IN" syntax because the low performance. Is there another way?
Note: date format is dd-mm-yyyy
Edit: I corrected the question (in bold).
This will exclude all customers where the INIT_DATE is less than today and the END_DATE > today.
with Curr_ord as
(
select co1.customer_id, co1.order_id
from customers_orders co1
inner join orders o1
on o1.id = co1.order_id
where o1.INIT_DATE <= sysdate
and o1.END_DATE > sysdate
)
select C1.*
from Customers C1
left join Curr_Ord CO2
on C1.Customer_ID = CO2.Customer_ID
where CO2.Customer_ID is null
Join the three tables and use conditional aggregation to check if all the orders for a customer are outdated.
select c.id,c.name
from customer_orders co
join orders o on o.id=co.order_id
join customers c on c.id=co.customer_id
group by c.id,c.name
having count(case when sysdate between co.init_date and co.end_date then 1 end) = 0
Why not just do the join?
SELECT DISTINCT C.CUSTOMER_ID
FROM customers c
JOIN Customers_Orders co on co.customer_id = c.customer_id
JOIN Orders od on od.order_id = co.order_id
WHERE Od.INIT_DATE <= SYSDATE
AND Od.END_DATE > SYSDATE
With the right indexing on orders, you might get the performance gain by putting the filter into the join:
SELECT DISTINCT C.CUSTOMER_ID
FROM customers c
JOIN Customers_Orders co on co.customer_id = c.customer_id
JOIN (SELECT od.order_id
from Orders
WHERE Od.INIT_DATE <= SYSDATE
AND Od.END_DATE > SYSDATE ) od on od.order_id = co.order_id
but now we're talking performance tuning strategies.... and in this case we would need to talk about your data profiles etc to get the optimal solution.