SQL query without foreign key in other table - mysql

i have problem with MySQL query, I have two tables - offers and bids:
offers bids
id status id offer_id user_id
1 new 1 1 1
2 new 2 1 2
3 rejected 3 2 1
4 accepted 4 4 4
5 new 5 5 2
6 new 6 6 3
7 new 7 7 1
Assuming that user_id = 2, I need all offers (from table offers)for this user_id which have status ="new", but without these offers which that user has bid (without offer 1 and offer 5)
I tried with "not exists" but without much success. Like:
SELECT distinct o.*
FROM offers o
LEFT JOIN bids AS b
ON o.id = b.offer_id
WHERE o.status = "new" AND (b.user_id!=2
OR NOT EXISTS (SELECT * FROM offers off WHERE b.offer_id = off.id))
And similiar ( i can get result when there is no other users that bid same offer),
but I cant get what I need.
EDIT:
As output in this case I need offers with IDs:
2 6 7 (offers 3 and 4 are not "new" and for offers 1 and 5 that user has already bids)

You don't need a join here. Its very simple
Select offers where status is new
Exclude those offers where user = 2 has bid
Query:
SELECT * FROM offers o
WHERE o.`status` = 'new' AND
o.id NOT IN (SELECT offer_id from bids b WHERE b.user_id = 2)

This should work:
SELECT distinct o.*
FROM offers o
WHERE o.status = "new" AND
o.id not in (select offer_id from bids where user_id = 2);
If you want to display for all the users then try following query:
SELECT distinct o.*
FROM offers o
Inner JOIN bids AS b
ON o.id = b.offer_id
WHERE o.status = "new" AND
Group by b.user_id
having o.id not in (select offer_id from bids b1 where b1.user_id = b.user_id);

SELECT distinct o.*
FROM offers o
JOIN bids b
ON o.id = b.offer_id
WHERE o.status = "new"
AND (o.id not in (select distinct(offer_id) from bids bi where bi.user_id=2 ))

Related

Get records that have 2 or more entries in a joining table matching a condition

customers
id INT PK
name VARCHAR
details
id INT PK
detail_name VARCHAR
customers_details
customer_id INT FK
detail_id INT FK
value INT
For each customer I have a set of details.
The following query will get all users that have the detail #2 equals to 10:
SELECT c.* FROM customers c
INNER JOIN customers_details cd ON cd.customer_id = c.customer_id
WHERE cd.detail_id = 2 AND cd.value = 10
My problem is that I need to get all customers that have 2 or more specific details. For example: I want to get all customers that have detail #2 = 10 AND detail #3 = 20.
Is there a simple way to do that using SQL?
I would do that:
select c.*
from customers_details cd
inner join customers c
on c.id = cd.customer_id
where cd.detail_id in (2,10)
group by cd.customer_id
having
sum(cd.detail_id = 2 and cd.value = 1) = 1
and sum(cd.detail_id = 10) = 1
What I do here is:
Grouping details by customer
Sum 1 if the condition is satisfied. If there is a detail = 2
Having filters only customers which has the both conditions
I use the WHERE clause in order to filter less results for HAVING filters again trying to avoid a full-scan.
Regards,
You're just looking for customers that have more than one detail ID, where one equals 2 and one equals 20?
SELECT c.customer_id, count (*) FROM customers c
INNER JOIN customers_details cd ON cd.customer_id = c.customer_id
WHERE cd.detail_id IN (2, 20)
GROUP BY c.customer_id
HAVING count(*) > 1
This should give you every customer_id that has a detail_id of 2 and a detail_id of 20
Use Group by and having
SELECT c.customer_id
, min(c.name) customer_name
, count(cd.customer_id) detailcount
FROM customers c
INNER JOIN customers_details cd ON cd.customer_id = c.customer_id
WHERE cd.Value is not null
group by c.customer_id
having COUNT(cd.customer_id)>=2
You can use count (distinct detail_id) = 2 to select all customers that have both detail ids
select c.* from customers_details cd
join customers c on c.id = cd.customer_id
where (detail_id = 2 and value = 10)
or (detail_id = 3 and value = 20)
group by customer_id
having count (distinct detail_id) = 2
select *
from customers as c
where exists (
select 1
from customer_details as cd
where
cd.customer_id = c.customer_id and
(detail_id = 2 and value = 10 or detail_id = 3 and value = 20)
having count(*) = 2
)
Be careful with parens. Not sure if some platforms might require a grouping on the subquery with a having clause. You can add a dummy group by like group by cd.customer_id if it does.

mysql group by and take specific record from right join table

I have database with following data structure with sample data. Each company have multiple members. The relationship is in the company_member table. Please note only required fields I have given below.
company
id title
1 company-1
2 company-2
company_member
companyid memberid
1 1
1 2
1 3
2 4
2 5
2 6
member
id firstname member_type_id
1 Name-1 2
2 Name-2 3
3 Name-3 3
4 Name-4 3
5 Name-5 2
6 Name-6 1
member_type
id user_level
1 0
2 1
3 2
I want list of unique companies with one member from each. But the member should be the lowest user_level within the company. i.e, following result should come;
result
companyid company_title memberid member_name user_level
1 company-1 1 Name-1 1
2 company-2 6 Name-6 0
I want to know how to get one member with lowest user level among the same company.
This is a bit complicated one, however this is one way of doing it using not exists, for bigger tables its wise to use not exits since using pivot tables it will not use index.
select
c.id,
c.title,
m.id as member_id,
m.firstname,
mt.user_level
from company_member_map cmp
join company c on c.id = cmp.companyid
join member m on m.id = cmp.memberid
join member_type mt on mt.id = m.member_type_id
where not exists
(
select 1 from company_member_map t1
join member t2 on t2.id = t1.memberid
join member_type t3 on t3.id = t2.member_type_id
where
t1.companyid = cmp.companyid
and t3.user_level < mt.user_level
)
DEMO
Finally I found solution:
select c.id companyid, c.title company_title, m.firstname member_name, mt.user_level
from company c
inner join company_member cm on cm.companyid = c.id
inner join member m on m.id = cm.memberid
inner join member_type mt on mt.id = m.member_type_id
inner join
(select c1.id companyid, mt1.user_level
from company c1
join company_member cm1 on cm1.companyid = c1.id
join member m1 on m1.id = cm1.memberid
join member_type mt1 on mt1.id = m1.member_type_id
group by c1.id,m1.id
order by user_level asc
) sq on c.id = sq.companyid and sq.user_level = mt.user_level
group by c.id;
Correct this, if anyone have better solution or simplified solution.
Check this SQL Fiddle

Intersection in mysql for multiple values

The intersect keyword is not available in mysql. I want to know how to implement the following in mysql db. My tables are:
customer(cid,city,name,state)
orders(cid,oid,date)
product(pid,price,productname)
lineitem(lid,pid,oid,totalquantity,totalprice)
I want the products bought by all the customers of a particular city 'X'. i.e. every customer in city 'x' should have bought the product. I managed to select the oid's and the pid's of customers living in that particular city. Now I should select the pid's which is present in all the oid's.
Example.
Oid Pid
2400 1
2400 2
2401 3
2401 1
2402 1
2403 1
2403 3
The answer from the above input should be 1 because it is present in all oid's. The query which I used to get the oid's and pid's:
select t.oid,l.pid
from lineitem l
join (select o.oid,c1.cid
from orders o
join (select c.cid
from customer c
where c.city='X') c1
where o.cid=c1.cid) t on l.oid=t.oid
Now I need to intersect all the oid's and get the result.The query should not be dependent on data.
Try:
select pid, count(*)
from (select t.oid, l.pid
from lineitem l
join (select o.oid, c1.cid
from orders o
join (select c.cid from customer c where c.city = 'X') c1
where o.cid = c1.cid) t
on l.oid = t.oid) x
group by pid
having count(*) = (select count(*)
from (select distinct oid
from lineitem l
join (select o.oid, c1.cid
from orders o
join (select c.cid
from customer c
where c.city = 'X') c1
where o.cid = c1.cid) t
on l.oid = t.oid) y) z
I think you can achieve what you want by using IN

Select only the latest version of the data with SQL join

I have two tables one containg offer information and the other containg products
something like this:
OFFER PRODUCTS
ID Number Version poID offer_id Product how_many
========================== ========================================
1 123 1 1 1 Apple 1
2 123 2 2 1 Banana 2
3 124 1 3 1 Orange 1
4 2 Apple 1
5 2 Banana 2
6 2 Orange 2
7 2 Kiwi 1
8 3 Apple 2
9 3 Banana 3
I would like a list of how many products that are currently offered.
Since OFFER(id = 2) is an update of (id = 1) only (id = 2) should be counted.
How should I best query this?
First you need to get all the latests offers:
select o.id
from offer o
where version = (select max(version)
from offer o2
where o2.number = o.number);
Based on the above you can then get all the products:
select p.*
from products p
where offer_id in (select o.id
from offer o
where version = (select max(version)
from offer o2
where o2.number = o.number));
If id and version correlate:
select sum(how_many) from products p
join offer on p.offer_id=offer.id
join (
select number, max(version) version from offer group by number
) x
on offer.id=x.id and offer.version = x.version
SELECT *
FROM products
WHERE offer_id = (SELECT MAX(id) FROM offer)
or, if you prefer the join syntax
SELECT p.*
FROM products p
INNER JOIN (SELECT MAX(id) id FROM offer) o ON p.offer_id = o.id
Edit (still not completely sure this is what you want without seeing your desired results)
SELECT p.*
FROM products p
INNER JOIN offer o on p.offer_id = o.id
INNER JOIN
(SELECT number, max(version)
FROM offer
GROUP BY number
) oMax ON o.number = oMax.number AND o.version = oMax.version
Try this:
select [list columns here]
from products p
join (select offernumber, max(id) as ID from offer group by offernumber) a
on a.id = p.offer_id
If you need addtional columns from offer other than the offernumber and the id:
select [list columns here]
from products p
join (select offernumber, max(id) as ID from offer group by offernumber) a
on a.id = p.offer_id
join offer o on o.id = a.id

SQL - How can I exclude results without subselect?

I stuck with sql query to list customer who bought product a but did not buy product b.
This is my table
Table customer
id_customer customer_name
1 name1
2 name2
3 name3
Table order
id_order id_customer product
1 1 a
2 1 b
3 2 b
4 3 a
I try:
SELECT * FROM customer, order WHERE customer.id_customer = order.id_customer
AND (order.product='a' AND order.product<>'b')
SELECT * FROM customer, order WHERE customer.id_customer = order.id_customer
AND (order.product IN ('a') AND order.product NOT IN ('b'))
[AND (order.product = 'a' AND order.product <> 'b')]
SELECT table1.id_customer, table1.customer_name FROM customer INNER JOIN order ON customer.id_customer = order.id_customer
WHERE order.product IN ('a') AND order.product NOT IN ('b')
[WHERE order.product = 'a' AND order.product <> 'b']
but it did not the right answer because it return:
1 1 a
4 3 a
The answer should be:
4 3 a
Anyone help me please. Thank you so much
You can use joins to filter out whether customer has each of product a, b, and then query the join to implement your particular logic. It would look something like this:
select distinct -- pull only unique customer information
C.*
from
customer C
left join -- orders of product a, which should exist
order OA on OA.id_customer = C.id_customer and OA.product = 'a'
left join -- orders of product b, which should not exist
order OB on OB.id_customer = C.id_customer and OB.product = 'b'
where -- orders of product a should exist
OA.id_order is not null
and -- orders of product b should not exist
OB.id_order is null
I don;t think we have all the details so here is a query that uses subqueries (ignoring question title) and returns customers rather than orders (ignoring expected resultset):
SELECT *
FROM customer AS c
WHERE EXISTS (
SELECT *
FROM order AS o
WHERE o.id_customer = c.id_customer
AND product = 'a'
)
AND NOT EXISTS (
SELECT *
FROM order AS o
WHERE o.id_customer = c.id_customer
AND product = 'b'
);