I am not sure about this query - sql

query to extract the data from the customer table if and only if one or more of the customers in the customer table are located in London
and my query is
select * from Customer
where 'London' = ANY (select city from Customer)
I know it's not the correct way but I wanted to know if this also works or not.
TIA

Your query works, so that is one way to express it (and rather clever). Here is an example.
More commonly, I think of this as anexists query:
select c.*
from Customer c
where exists (select 1 from Customer c2 where c2.city = 'London');
This will return all customers from any city, even those not in London.
It is quite possible that you just want to return customers in London, in which case a simple where city = 'London' suffices.

select * from Customer where city ='London' and 1 > (select count(*) from Customer where city='London');

Related

Postgres Question: Aren't both a and b correct?

For questions below, use the following schema definition.
restaurant(rid, name, phone, street, city, state, zip)
customer(cid, fname, lname, phone, street, city, state, zip)
carrier(crid, fname, lname, lp)
delivery(did, rid, cid, tim, size, weight)
pickup(did, tim, crid)
dropoff(did, tim, crid)
It's a schema for a food delivery business that employs food carriers (carrier table).
Customers (customer table) order food from restaurants (restaurant table).
The restaurants order a delivery (delivery table); to deliver food from restaurant to customer.
The pickup table records when carrier picks up food at restaurant.
The dropoff table records when carrier drops off food at customer.
1.Find customers who have less than 5 deliveries.
a. select cid,count()
from delivery
group by cid
having count() < 5;
b. select a.cid,count()
from customer a
inner join delivery b
using(cid)
group by a.cid
having count() < 5;
c. select a.cid,count()
from customer a
left outer join delivery b
on a.cid=b.cid
group by a.cid
having count() < 5;
d. select cid,sum(case when b.cid is not null then 1 else 0 end)
from customer a
left outer join delivery b
using (cid)
group by cid
having sum(case when b.cid is not null then 1 else 0 end) < 5;
e. (write your own answer)
No, they are not correct. They miss customers who have had no deliveries.
The last is the best of a bunch of not so good queries. A better version would be:
select c.cid, count(d.cid)
from customer c left outer join
delivery d
on c.cid = d.cid
group by c.cid
having count(d.cid) < 5;
The sum(case) is over kill. And Postgres even offers a better solution than that!
count(*) filter (where d.cid is not null)
But count(d.cid) is still more concise.
Also note the use of meaningful table aliases. Don't get into the habit of using arbitrary letters for tables. That just makes queries hard to understand.

SQL server where clause (compare more values in more values)

SELECT * FROM Customers
WHERE ('Paris','London', 'Dublin', 'Venice') in (SELECT city FROM Europe)
SELECT city FROM Europe return more than one value,
how can I do this?
i dont want to repeat the condition like:
WHERE ('Paris') in (SELECT city FROM Customers)
or ('London') in (SELECT city FROM Customers)
or ('Dublin') in (SELECT city FROM Customers) or ....
Your second select is redundant, and you can just "flip" in condition.
So equivalent of your query is:
SELECT * FROM Customers
WHERE city in ('Paris','London', 'Dublin', 'Venice')
Update.
Based on logic you've disclosed in comments, you query should be something like:
select * from Customers
where exists(select top 1 * from Europe where city in ('Paris','London', 'Dublin', 'Venice'))
Exactly as was stated: if exists at least one of city in ('Paris','London', 'Dublin', 'Venice') in Europe then everything from Customers will be selected, else nothing will be selected.
You can just use in and the column name. IN is equivalent to or, which is city = 'Paris' or city = 'London'.. in your case.
SELECT * FROM Customers
WHERE city in ('Paris','London', 'Dublin', 'Venice')
Edit: Using exists
SELECT c.* FROM Customers c
WHERE exists (select 1 from Europe where city = c.city
and city in ('Paris','London', 'Dublin', 'Venice')

Select all customers loyal to one company?

I've got tables:
TABLE | COLUMNS
----------+----------------------------------
CUSTOMER | C_ID, C_NAME, C_ADDRESS
SHOP | S_ID, S_NAME, S_ADDRESS, S_COMPANY
ORDER | S_ID, C_ID, O_DATE
I want to select id of all customers who made order only from shops of one company - 'Samsung' ('LG', 'HP', ... doesn't really matter, it's dynamic).
I've come only with one solution, but I consider it ugly:
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company = "Samsung" )
EXCEPT
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company != "Samsung" );
Same SQL queries, but reversed operator. Isn't there any aggregate method which solves such query better?
I mean, there could be millions of orders(I don't really have orders, I've got something that occurs more often).
Is it efficient to select thousands of orders and then compare them to hundreds of thousands orders which have different company? I know, that it compares sorted things, so it's O( m + n + sort(n) + sort(m) ). But that's still large for millions of records, or isn't?
And one more question. How could I select all customer values (name, address). How can I join them, can I do just
SELECT CUSTOMER.* FROM CUSTOMER JOIN ( (SELECT...) EXCEPT (SELECT...) ) USING (C_ID);
Disclaimer: This question ain't homework. It's preparation for the exam and desire to things more effective. My solution would be accepted at exam, but I like effective programming.
I like to approach this type of question using group by and a having clause. You can get the list of customers using:
select o.c_id
from orders o join
shops s
on o.s_id = o.s_id
group by c_id
having min(s.s_company) = max(s.s_company);
If you care about the particular company, then:
having min(s.s_company) = max(s.s_company) and
max(s.s_company) = 'Samsung'
If you want full customer information, you can join the customers table back in.
Whether this works better than the except version is something that would have to be tested on your system.
How about a query that uses no aggregate functions like Min and Max?
select C_ID, S_ID
from shop
group by C_ID, S_ID;
Now we have a distinct list of customers and all the companies they shopped at. The loyal customers will be the ones who only appear once in the list.
select C_ID
from Q1
group by C_ID
having count(*) = 1;
Join back to the first query to get the company id:
with
Q1 as(
select C_ID, S_ID
from shop
group by C_ID, S_ID
),
Q2 as(
select C_ID
from Q1
group by C_ID
having count(*) = 1
)
select Q1.C_ID, Q1.S_ID
from Q1
join Q2
on Q2.C_ID = Q1.C_ID;
Now you have a list of loyal customers and the one company each is loyal to.

sql query to select matching rows for all or nothing criteria

I have a table of cars where each car belongs to a company. In another table I have a list of company locations by city.
I want to select all cars from the cars table whose company has locations on all cities passed into the stored procedure, otherwise exclude those cars all together even if it falls short of one city.
So, I've tried something like:
select id, cartype from cars where companyid in
(
select id from locations where cityid in
(
select id from cities
)
)
This doesn't work as it obviously satisfies the condition if ANY of the cities are in the list, not all of them.
It sounds like a group by count, but can't make it work with what I tried.
I"m using MS SQL 2005
One example:
select id, cartype from cars c
where ( select count(1) from cities where id in (...))
= ( select count(distinct cityid)
from locations
where c.companyid = locations.id and cityid in (...) )
Maybe try counting all the cities, and then select the car if the company has the same number of distinct location cities are there are total cities.
SELECT id, cartype FROM cars
WHERE
--Subquery to find the number of locations belonging to car's company
(SELECT count(distinct cities.id) FROM cities
INNER JOIN locations on locations.cityid = cities.id
WHERE locations.companyId = cars.companyId)
=
--Subquery to find the total number of locations
(SELECT count(distinct cities.id) FROM cities)
I haven't tested this, and it may not be the most efficient query, but I think this might work.
Try this
SELECT e.*
FROM cars e
WHERE NOT EXISTS (
SELECT 1
FROM Cities p
WHERE p.location = e.Location
)

Creating table using select statement from multiple tables

I have this university task to create table using SELECT statement from multiple tables, but it's not as simple... here's basic info:
I'm using 2 tables -
CITY(city_ID, name);
PERSON(person_ID, name, surname, city_ID);
--city_ID is FK indicating in which city person was born.
Now my task is to create new table
STATISTICS(city_ID, city_name, number_of_births);
--number_of_births is basically a count of people born in each city
Problem is that I have to use only SELECT statement to do so.
I've tried something like this: (I'm well aware that this cannot possibly work but as to give you a better idea where I'm stuck)
CREATE TABLE Statistics AS
(SELECT city.city_ID, city.name as "city_name", number_of_births AS
(SELECT COUNT(*) FROM person WHERE person.city_id = city.city_id)
FROM city, person);
For SQL Server you can do SELECT * INTO. Something like this:
SELECT
*
INTO Statistics
FROM (
SELECT
city.city_ID,
city.name as "city_name",
(SELECT COUNT(*) FROM person WHERE person.city_id = city.city_id) as 'number_of_births'
FROM city
inner join person on city.city_id = person.city_id
) t1
(Posted on behalf of the question author).
Ok, this got really messy. Dave Zych's answer was correct when rewritten in Oracle dialect.
CREATE TABLE Statistics AS SELECT * FROM (
SELECT DISTINCT
city.city_ID,
city.name AS "City_name",
(SELECT COUNT(*) FROM person WHERE person.city_ID = city.city_ID) AS "number_of_births"
FROM city INNER JOIN person ON city.city_ID = person.city_ID);