SQL: how to use two conditions whith dependences? - mysql

I have database where is unique customer ID.
I what to know what products they have bought before specified product. I have a list when specified ID has bought bananas I want to search all products and dates before that.
Example I have data:
CustomerID Product Date
123 banana 2015-03-15
111 banana 2014-07-09
321 banana 2013-04-03
How I can write SQL command search all products what Customer have bought before that date?
Example
CustomerID Product Date
123 Apple 2014-05-07
123 Kiwi 2014-05-06
123 Pen 2012-12-12
111 Pen 2014-07-07
111 Milk 2010-01-30
321 Milk 2012-02-12

This should work for you. The table name is contrived, so you will need to replace it.
SELECT CustomerID, Product, Date
FROM ProductTable p1
WHERE Date < (
SELECT MAX(Date)
FROM ProductTable p2
WHERE p2.CustomerID = p1.CustomerID AND p2.Product = 'banana'
)
ORDER BY CustomerID, Date;

#Peter Abolins's answer is correct, but does not handle the case when the customer has never bought a banana yet.
To handle this case, the request would become:
SELECT CustomerID, Product, Date
FROM ProductTable p1
WHERE Date < (
SELECT IFNULL (
(SELECT MAX(Date)
FROM ProductTable p2
WHERE p2.CustomerID = p1.CustomerID AND p2.Product = 'banana'),
'9999-12-31'
)
)
ORDER BY CustomerID, Date;
PS: I know that this should be a comment, but I cannot comment with this account yet.

I'm not sure if this is what you want but give it a try and look at the results:
SELECT * FROM tableA AS a
JOIN tableA AS b
ON a.CustomerID = b.CustomerID AND a.Date > b.Date
ORDER BY a.CustomerID, a.Product, a.Date

You have two tables, the first table with a list of customer ID, and dates for a specified product, and the second table with the history of product sold to that customer.
We will call them respectively LIST and HIST, you can get your desired output with:
SELECT p1.CustomerID, p2.Product, p2.Date
FROM LIST p1
left join HIST p2 on p2.CustomerID = p1.CustomerID AND P1.Date > P2.Date
ORDER BY p1.CustomerID, p2.Date;

Related

How to count matching Sell-Orders for all Buy-Orders with dynamic attributes?

I want to retrieve all buy orders with a count of matching buy orders in a single query.
A match would be a sell order that satisfies all attributes (greater or equal) and is cheaper than the buy order. Is that even possible?
This is my table structure:
Attributes
id
name
1
Area (m2)
2
Rooms
...
...
Sell Orders
id
title
price
...
1
Flat #1
500.000,00€
...
2
House #1
1.000.000,00€
...
...
....
....
...
Sell Order Attributes
sell_order_id
attribute_id
value
...
1
1
90
...
1
2
3
...
2
1
239
...
2
2
5
...
...
...
...
...
Buy Orders
id
offer
...
1
600.000,00€
...
2
150.000,00€
...
Buy Order Attributes
buy_order_id
attribute_id
value
...
1
1
80
...
1
2
2
...
2
1
200
...
2
2
3
...
...
...
...
...
I tried solving it in MySQL Workbench but I could not figure it out
I assume that the sell order id and buy order id is related. If not, then there is no relations in your data between sell and buy tables. You can try something like below to get the raw answer. First cte creates marker for all attributes. Second CTE gets all sales ids that fulfil all the attribute needs. Then final select gets the cases where buy orders are in line with sales attribute needs and price less than the buy order.
with cte as (
select s.*
case
when a.[attribute_id] = 'whatever attribute you choose' and a.value >= 'whatever the benchmark is' then 1
when a.[attribute_id] = 'whatever 2nd attribute you choose' and a.value >= 'whatever the benchmark is' then 1
else 0
end as marker
from [Sell Orders] s
inner join [Sell Order Attributes] a on s.id = a.sell_order_id
),
cte2 as (
select id , sum(marker)
from cte
group by id
having sum(marker) = 2 --however many attributes you are testing
)
select *
from [Buy Orders] b on b.id = s.id
inner join [Buy Order Attributes] c on b.id = c.buy_order_id
inner join cte2 t on t.id = b.id
Where t.price < b.price
As you don't store price and offer as decimal or other numeric types you need always to cast it, which will take some time, besides monetary datatypes arent't supported, so you should redesign your tables.
the rest is a lot of joins with the correct ON clause.
It will compare the price against the offer and all attributes that match
SELECT DISTINCT s.*,b.*
FROM Sell_Orders s JOIN Sell_Order_Attributes sa ON sa.`sell_order_id` = s.`id`
JOIN Buy_Orders b ON CAST( REPLACE(REPLACE(REPLACE(b.`offer`,'€',''),'.',''),',','.') AS DECIMAL(20,2)) >= CAST( REPLACE(REPLACE(REPLACE(s.price,'€',''),'.',''),',','.') AS DECIMAL(20,2)) JOIN Buy_Order_Attributes ba ON ba.`buy_order_id` = b.`id`
and ba.`attribute_id` = sa.`attribute_id`and sa.`value` >= ba.`value`
id
title
price
id
offer
1
Flat #1
500.000,00€
1
600.000,00€
fiddle

MYSQL sum/Count fails inside inner join group by

I have a table that contains sales records:
Sale ID
EmployeeId(FK)
Employee 2
...
1
101
Null
...
2
102
Null
...
3
300
Bob
...
...
...
...
...
I have another table that contains employee records:
EmployeeId
EmployeeName
...
101
Amanda
...
102
Bob
...
...
...
...
300
cicilia
...
...
...
...
I'm trying to do a select where i get all sales and group them by employees for performance analysis. So far i managed to get right the employees and their sale counts and totals. The problem is the third column in my sales record is called employee2, it can be null as not every sale has another employee assisting. It is not indexed to the employee table unlike the second column.
So for example in my query below, the expected results should be Amanda has 1 salecount, 0 helpCount, meanwhile Boss has 1 salecount, 1 helpCount, and cicillia has 1 salecount, 0 helpcount. But im getting 1 salecount for all which is correct, but 0 helpcounts for bob. This is my query so far:
select employee.employee_id,
employee.employee_Name,
count(sale.sale_id) as saleCount,
sum(sale.grand_total) as totalSalesRevenue,
sum(CASE WHEN sale.employee2 = employee.employee_Name THEN 1
ELSE 0 END) as helperEmpCount
from employee
inner join sale on employee.employee_id = sale.employee_id
group by employee.employee_id;
The result set, where helpCounts should not be 0.
Im running a mysql 8.0 database.
Edit: I have found a workaround, albeit a very unefficient one. If i change my count to a nested select it works, but this decreases performance by quite a bit considering i have a lot of employees.
New query:
select employee.employee_id,
employee.employee_Name,
count(sale.sale_id) as saleCount,
sum(sale.grand_total) as totalSalesRevenue,
(select count(sale.employee2) from sale where sale.employee2= employee_Name) as helperEmpCount
from employee
inner join sale on employee.employee_id = sale.employee_id
group by employee.employee_id;
Any idea how to make it more efficient?
You can join the tables on either of the 2 conditions and use conditional aggregation:
SELECT e.employee_id,
e.employee_Name,
SUM(s.employee_id = e.employee_id) AS saleCount,
SUM(CASE WHEN s.employee_id = e.employee_id THEN s.grand_total ELSE 0 END) AS totalSalesRevenue,
SUM(s.employee2 = e.employee_Name) AS helperEmpCount
FROM employee e LEFT JOIN sale s
ON s.employee_id = e.employee_id OR s.employee2 = e.employee_Name
GROUP BY e.employee_id;

How to Join My Invoice and Invoice Product table with sql query..?

I have two table invoice and invoice product table, i want to join my two table with respect to each invoice id.
I have tried to write sql query but it is wrong.
SELECT invoice.invoice_id, invoice_product.product_name
FROM invoice, invoice_product
WHERE invoice.invoice_id = invoice_product.invoices_id
I want to show my actually result like this.
Invoice_id | Invoice_name | Product_name | Created Date
========== |============= |=============================|==============
1 | Test 1 | Product1 ,product 2 | 2019-05-02
2 | Test 2 | New Product ,New Product | 2019-05-02
invoice table:
invoice_product table:
Avoid jointure with your actual syntax, this is too old.
I do not recommand to have non-atomic values but the GROUP_CONCAT function is doing the work for you.
SELECT invoice.invoice_id, GROUP_CONCAT(IP.product_name), I.created_at
FROM invoice AS I
JOIN invoice_product AS IP
ON I.invoice_id = IP.invoices_id
GROUP BY IP.invoices_id
You need to use a GROUP_CONCAT to get the list of products like that, grouping by invoice number. This will work:
SELECT i.invoice_id, i.invoice_name, GROUP_CONCAT(ip.product_name) AS products, i.created_at
FROM invoice i
JOIN invoice_product ip ON i.invoice_id = ip.invoices_id
GROUP BY i.invoice_id
Output:
invoice_id invoice_name products created_at
1 Test 1 Product 1,Product 2 2019-05-02 00:00:00
2 Test 2 Product New,Product New New 2019-05-02 00:00:00
Demo on dbfiddle
Note that implicit JOIN syntax using comma has been deprecated for a while, it is better to write explicit JOINs instead.
use group_concat()
SELECT invoice.invoice_id, group_concat(invoice_product.product_name)
FROM invoice join invoice_product
on invoice.invoice_id = invoice_product.invoices_id
group by invoice.invoice_id

SQL Select Statement customer with two or more banks

I have this table
CustomerID CustomerName Bank Amount
1 Martin BDO Php 55.00
1 Martin CBA Php 150.00
2 Grace BDO Php 45.00
2 Grace BDO Php 4100.00
3 Blake BPI Php 120
I need a sql statement that will display customer with accounts on two different banks.
The result should be
CustomerID CustomerName Bank Amount
1 Martin BDO Php 55.00
1 Martin CBA Php 150.00
How can I get this result?
You can use GROUP BY with HAVING to do this, e.g.:
SELECT *
FROM customer
WHERE customerID IN (
SELECT customerID
FROM customer
GROUP BY customerID
HAVING COUNT(DISTINCT(Bank)) > 1
);
There are several different ways you can get the result that you want. You could join on a subquery that gets a list of CustomerIds with more than one distinct Bank:
select
m1.CustomerId,
m1.CustomerName,
m1.Bank,
m1.Amount
from mytable m1
inner join
(
select
CustomerId
from mytable
group by CustomerId
having count(distinct Bank) >= 2
) m2
on m1.CustomerId = m2.CustomerId;
Or you could use a WHERE EXISTS to also get the result:
select
m.CustomerId,
m.CustomerName,
m.Bank,
m.Amount
from mytable m
where exists (select 1
from mytable m2
where m.CustomerId = m2.CustomerId
and m.Bank <> m2.Bank);
Here is a demo

Joining over three table with sum() subquery

I'm having trouble getting a query to work where data is pulled from two tables, with a 3rd table in the middle. Let me show you what I mean.
*Table companies*
id int PK
name text
*Table projects*
id int PK
company_id int FK
project_name text
*Table hours_worked*
id int pk
user_id int FK
project_id int FK
hours float
date_worked datetime
*Table users*
id int PK
user_name text
Basically, what I need is a query that pulls the total amount of hours worked per company based on a user ID.
Note that the table_hours worked can have multiple submissions per day per project. For example, a few rows might look like
id project_id user_id hours date_worked
1 1 1 2 20-08-2012
2 1 1 1.5 20-08-2012
3 2 1 3 21-08-2012
4 2 2 12 22-08-2012
My desired result would be a query that returns something like this:
company_name total_hours
Bobs Kitchens 25
Mikes Bikes 67
Which returns the total number of hours worked per company (not project) for say, a user with the user ID of 1.
Here is the following query I've tried with no avail:
SELECT DISTINCT companies.name as company_name,
companies.id as company_id,
(
SELECT SUM(hours_worked.hours) FROM hours_worked
WHERE projects.id = hours_worked.project_id
AND projects.company_id = company_id
) as total_hours
FROM hoursworked, companies, projects
WHERE projects.company_id = company_id
AND projects.company_id = projects.company_id
AND hours_worked.user_id = 1
GROUP BY companies.id
This is giving me an odd result where a really weird number appears to be displaying for every total_hours field. 75 is not the correct total hours for any company!
company_name total_hours
Mikes Kitchen 75
Charlies Bikes 75
..... 75
Any help would be greatly appreciated!
Try this:
SELECT c.name company_name, u.user_name, SUM(h.hours) total_hours
FROM projects p
INNER JOIN companies c ON p.company_id = c.id
INNER JOIN hours_worked h ON p.id = h.project_id
INNER JOIN users u ON h.user_id = u.id
GROUP BY c.id, u.id
I was such a fool..it was actually a lot easier than I expected. Hurray for over thinking.
The query I've used is:
SELECT SUM(hours_worked.hours) as 'total_hours',
companies.name
FROM companies, hours_worked, projects
WHERE companies.id = projects.company_id
AND hours_worked.project_id = projects.id
AND hours_worked.uid = 1
GROUP BY companies.id ORDER BY companies.name DESC