For example: in my database I have 3 tables: COMPANY, COUPON and COMPANY_COUPON.
COMPANY table has fields: ID and NAME, COUPON table has: ID, TITLE and TYPE, COMPANY_COUPON table has: ID of the COMPANies and ID of the COUPONs that they own.
So, in java to get all coupons of the company I use command:
SELECT coupon_id FROM company_coupon WHERE company_id = ?
And put it into Collection.
But I need something to get all coupons of the company by the type,
something like:
SELECT * FROM company_coupon WHERE company_id = 1 AND coupon_id = (SELECT * FROM coupon WHERE type = camping)
of course this one is not working, but I'm looking for something like that.
I know that i can get all coupons of the company and put them into Collection and then just delete all coupons that not equals to the specified type, but is there any way to do this process in database by SQL commands?
You might want to use WHERE IN here:
SELECT *
FROM COMPANY_COUPON
WHERE COMPANY_ID = 1 AND COUPON_ID IN (SELECT ID FROM COUPON WHERE TYPE = 'CAMPING');
You could also use EXISTS, which is probably the best way to write your logic:
SELECT cc.*
FROM COMPANY_COUPON cc
WHERE
cc.COMPANY_ID = 1 AND
EXISTS (SELECT 1 FROM COUPON c WHERE c.TYPE = 'CAMPING' AND c.ID = cc.COUPON_ID);
Using EXISTS might outperform doing a join between the two tables, because the database can stop as soon as it finds the very first match.
Use only one column with an IN operator
SELECT *
FROM COMPANY_COUPON
WHERE COMPANY_ID = 1
AND COUPON_ID IN (SELECT COUPON_ID FROM COUPON WHERE TYPE = CAMPING)
I think you just want a join:
SELECT cc.COUPON_ID
FROM COMPANY_COUPON cc JOIN
COUPON c
ON cc.COUPON_ID = c.ID
WHERE cc.COMPANY_ID = ? AND c.TYPE = ?;
Related
I have a table called customer_transactions and a table called blacklist.
The customer_transactions table has a column called atm_name.
Both tables share a unique key called id.
How can I intersect the two tables in such a way that the query shows me
customers that appear on both tables.
a corresponding column that displays the times that they had used a
certain atm alongside the atm's name
(for instance: id_1 -- bank of america -- 2; id_1 -- citibank -- 3;
id_2 -- bank of america -- 1; id_2 -- citibank -- 4, etcetera).
I have something like this
SELECT id,
atm_name,
count(atm_name) as atm_count
FROM customer_transactions
GROUP BY id, atm_name
How can I INTERSECT this table with the blacklist table and maintain what I currently have as output?
Thanks in advance.
You seem to want a join. Assuming that column id relates the two tables, and that it is a unique key in blacklist, you can do:
select ct.id, ct.atm_name, count(*) as atm_count
from customer_transactions ct
inner join blacklist b on b.id = ct.id
group by ct.id, ct.atm_name
You can also express this logic with exists and a correlated subquery:
select ct.id, ct.atm_name, count(*) as atm_count
from customer_transactions ct
where exists (select 1 from blacklist b where b.id = ct.id)
group by ct.id, ct.atm_name
I am writing a Redshift query which require use of multiple case statements.
Pretext:
Customers can associated with more than one organizations like, sweet or salt etc.
Ask :
We have to check that customers associated with 'SWEETS' organization are picked first, if no affiliation with 'SWEETS' is available , than we have to take id of that organization where flag = 1.
I have to use a case statement in redshift to derive the result.
There are three different tables, customer table, organization table and 3 table that determines how customers are associated with organization.
![enter image description here][1]
Code that I have tried is below , but after executing this , I am still getting the two organization ids, instead of one id which should be of sweet org.
SELECT customer_id
, organization_id
FROM customer_details AS customer
LEFT JOIN organization AS org
ON customer.customer_id
AND organization_id = CASE WHEN organization_id IN (SELECT organization_id
FROM organization_type
WHERE organization_type = 'SWEET')
THEN organization_id
ELSE org.organization_id END
You can use window functions:
select customer_id, organization_id
from (select c.customer_id, o.organization_id,
row_number() over (partition by o.customer_id order by o.organization_type = 'SWEET' desc) as seqnum
from customer_details c left join
organization o
on c.customer_id = o.organization_id
) co
where seqnum = 1;
Let's say I have two tables (1 to many): table company with fk id and table product with fk id and also fields sId and tId (if sId has data tId is null and vice versa, not sure if it matters).
I want every company that has products with, for example sId=1, sId=2, tId=3 and tId=4.
So for a company to be eligible it has to have products with sId=1 and sId=2 and tId=3 and tId=4. If one is missing it shouldnt appear.
I tried joining the tables and doing
where pro.sId in ('1', '2')
and pro.tId in ('3','4')
But it doesn't give me any companies. Any help would be appreciated.
You can use aggregation. Assuming no duplicate sld or tld per company_id in the products table:
select c.id
from companies c
inner join products p on p.company_id = c.id
where p.sld in (1, 2) or p.tld in (3, 4)
group by c.id
having count(*) = 4
If there are duplicates, you can change the having clause to:
having count(distinct p.sld) = 2 and count(distinct p.tld) = 2
There are many ways to achieve this. One is:
select * from company where id in
(
select company_id from product where sid = 1
intersect
select company_id from product where sid = 2
intersect
select company_id from product where tid = 3
intersect
select company_id from product where tid = 4
);
Another:
select * from company
where id in (select company_id from product where sid = 1)
and id in (select company_id from product where sid = 2)
and id in (select company_id from product where tid = 3)
and id in (select company_id from product where tid = 4);
I have a table of customers with their customer contact options.
Customers can be contact in one of three ways via:
Telephone (1)
SMS (2)
Email (3)
the FK id is in brackets.
If I wanted to pull out a list of distinct customer id's for both say SMS and Email I could do the following:
SELECT DISTINCT customer_id
FROM contact_options
WHERE contact_option_type_id IN (2,3)
But how do I do the inverse? Say I want a (DISTINCT) list of customers who don't have a Telephone contact. Can I do this without using a sub-query?
I realise the example is contrived, in practice I have very many different contact options (around 80).
One option is to use aggregation:
SELECT customer_id
FROM contact_options
GROUP BY customer_id
HAVING SUM(CASE WHEN contact_option_type_id = 1 THEN 1 ELSE 0 END) = 0;
We can also try doing this using EXISTS:
SELECT DISTINCT customer_id
FROM contact_options c1
WHERE NOT EXISTS (SELECT 1 FROM contact_options c2
WHERE c1.customer_id = c2.customer_id AND c2.contact_option_type_id = 1);
You can use not exists:
select distinct c.customer_id
from contact_options c
where not exists (select 1
from contact_options
where customer_id = c.customer_id and
contact_option_type_id = 1
);
I don't think exists has performance issue if you have proper indexing delcared.
I have a candidate table say candidates having only id field and i left joined profiles table to it. Table profiles has 2 fields namely, candidate_id & name.
e.g. Table candidates:
id
----
1
2
and Table profiles:
candidate_id name
----------------------------
1 Foobar
1 Foobar2
2 Foobar3
i want the latest name of a candidate in a single query which is given below:
SELECT C.id, P.name
FROM candidates C
LEFT JOIN profiles P ON P.candidate_id = C.id
GROUP BY C.id
ORDER BY P.name;
But this query returns:
1 Foobar
2 Foobar3
...Instead of:
1 Foobar2
2 Foobar3
The problem is that your PROFILES table doesn't provide a reliable means of figuring out what the latest name value is. There are two options for the PROFILES table:
Add a datetime column IE: created_date
Define an auto_increment column
The first option is the best - it's explicit, meaning the use of the column is absolutely obvious, and handles backdated entries better.
ALTER TABLE PROFILES ADD COLUMN created_date DATETIME
If you want the value to default to the current date & time when inserting a record if no value is provided, tack the following on to the end:
DEFAULT CURRENT_TIMESTAMP
With that in place, you'd use the following to get your desired result:
SELECT c.id,
p.name
FROM CANDIDATES c
LEFT JOIN PROFILES p ON p.candidate_id = c.id
JOIN (SELECT x.candidate_id,
MAX(x.created_date) AS max_date
FROM PROFILES x
GROUP BY x.candidate_id) y ON y.candidate_id = p.candidate_id
AND y.max_date = p.created_date
GROUP BY c.id
ORDER BY p.name
Use a subquery:
SELECT C.id, (SELECT P.name FROM profiles P WHERE P.candidate_id = C.id ORDER BY P.name LIMIT 1);