Subqueries on subqueries - sql

I'm trying to create a select statement
I need to gather from one table a record that equals the same code used in another table.
better put, a client selects from a drop down list a city and a category for that city.
When the client clicks next, the various places in that city that meet that category are displayed.
but I can't figure out where I'm going wrong.
now when the client selects a city, there are two records that read for each city, a proper city code and a post box code that has 'bx' as the first letters
in my first query, to eliminate duplicates, I say
select c.[Description] from city c
where c.Provincecode like 'EC' and
c.citycode in (select c.citycode from City c
where SUBSTRING(c.citycode,0,3) not like 'bx')
that gives me one city name.
but now, if the client has chosen, for instance, cash only places to see,
there should only be one record showing up in the results
but try as I might, I can't get the right syntax
I've tried:
select c.[Description] from city c
where c.Provincecode like 'EC' and
c.citycode in (select c.citycode from City c
where SUBSTRING(c.citycode,0,3) not like 'bx')
and exists (select * from Customers cu
where cu.Category like 'SC' and cu.Province like 'EC')
but that brings more results than anticipated
this is done using an access database, but I am using SQL to do the coding, which I re-write into access. that's not a problem
so if someone could please provide the SQL answer, I can do the rest from there
I'm not sure if I'm supposed to do a join.
I did try
select * from
(select c.[Description] from city c
where c.Provincecode like 'EC' and
c.citycode in (select c.citycode from City c
where SUBSTRING(c.citycode,0,3) not like 'bx')) x
join Customers on province=city.provincecode where Category like 'SC'
but I get errors for multi-part identifier could not be bound
EDIT
this is the new query
select *
from
(
select c.*
from city c
where c.Provincecode like 'EC'
and c.citycode in
(
select c.citycode
from City c
where SUBSTRING(c.citycode,0,3) not like 'bx'
)
) x
join
Customers
on province=x.Provincecode
where Category like 'SC'
what is returned is
as you can see, there are too many reults that have C Strydom as the customer, but all the cities are there
for this particular example, only one record should be shown, the second one

The issue was an incomplete JOIN (see question comments for details). The query that worked was
select *
from
(
select c.*
from city c
where c.Provincecode like 'EC'
and c.citycode in
(
select c.citycode
from City c
where SUBSTRING(c.citycode,0,3) not like 'bx'
)
) x
INNER JOIN
Customers
ON Customers.province=x.Provincecode
AND Customers.city=x.Citycode
where Category like 'SC'

Although I don't like using SELECT *, you know more of the actual columns you DO want, I leave that to you. The query should be simple as you are primarily looking at the "City" table for a specific province code but doesn't start with "bx". Just have that in your where clause... you can test multiple things about a record without having to join to itself on some other criteria. Once you have that, then a simple join to the customer table for the category you are limiting to.
select *
from
city c
JOIN Customers CU
on c.ProvinceCode = CU.Province
AND CU.Category like 'SC'
where
c.ProvinceCode like 'EC'
and NOT substr( c.CityCode,0,3 ) = 'bx'
Now, your issue of the multiple records per customer. If all you are joining on is the province code to the customer table, you WILL get a Cartesian result... but if you join to the ProvinceCode AND City of the customer, you'll get only the single one that matches... but we don't have the customer table detail to confirm that column relationship.

Related

SELECT "NOT IN", INNER JOIN and COUNT in SQL Query

I am trying to select which co-ordinates from OA table are NOT found in the CUSTOMER address table.
SELECT DISTINCT
OA.CO_ORDS
FROM
CUSTOMER
INNER JOIN
OA ON customer.address=oa.co_ords
ORDER BY ID ASC;
Returns the co-ordinates which ARE in the customer table. How do I return those that are not in the customer table?
Am I also able to COUNT how many of customers are is in each co-ordinate (The co-ords are not specific and not accurate, this is purely for query testing only)
SELECT DISTINCT
OA.CO_ORDS
FROM
CUSTOMER
INNER JOIN
OA ON customer.address=oa.co_ords
ORDER BY ID ASC;
We can use NOT EXISTS to find those co-ordinates which don't appear in the customer table:
SELECT co_ords
FROM oa
WHERE
NOT EXISTS
(SELECT 1 FROM customers
WHERE address = oa.co_ords)
ORDER BY id;
In order to count how many customers belong to a certain co-ordinate, we can use COUNT with GROUP BY, something like this:
SELECT c.address, COUNT(*)
FROM customers c
JOIN oa
ON c.address = oa.co_ords
GROUP BY c.address;
It could be better to count a specific column instead of *.
It could also be better to use an IN clause instead of JOIN the tables:
SELECT c.address, COUNT(*)
FROM customers c
WHERE address IN
(SELECT co_ords FROM oa)
GROUP BY c.address;
Such details depend on your exact table structure, you should please try this out or provide more details.
You could also do:
SELECT co_ords
FROM oa
MINUS
SELECT address
FROM customers;
which can sometimes be faster than doing an anti-join. Note that MINUS does a distinct on the resultset.

Could this be re-written without the union operator?

Consider this DB at https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all
The goal is to write a query to list all the cities in that DB.
Can the query below be re-written without using the union operator? in ANSI SQL or any other ones. I just want to get a general idea. Thank you
SELECT City, country FROM Customers
UNION
SELECT City, country FROM Suppliers
order by city, country
The only other way (I can think of) to do it is with a FULL OUTER JOIN:
SELECT DISTINCT
COALESCE(c.City, s.City) AS City,
COALESCE(c.country, s.country) AS country
FROM Customers c FULL JOIN Suppliers s
ON s.City = c.City AND s.country = c.country
Note that UNION is the correct method for this requirement and that FULL OUTER JOIN is not supported by databases like MySql and SQLite.

How to apply join on three tables?

I have three tables customer, address, and city and I want to find the city each customer is from. So I am using two joins but after the query execution I find out that no two customers have the same city according to my query can someone please help me is my query ok.
I am using pagila database.
select c.first_name , ct.city
from customer c
join address a on c.address_id=a.address_id
join city ct on a.city_id=ct.city_id
Is this what are you expecting?
select distinct c.first_name , ct.city from customer c
join address a on c.address_id=a.address_id
join city ct on a.city_id=ct.city_id

Merging two querying

I will introduce my problem with a simple example.
I have two generic queries on the same table, say table 'customers'
Defined 'plushes' a table containing information about in-store plushes, the following first query retrieves for a certain subset of Customers, say first subset, their preferred plush.
WITH preferences
AS
(
SELECT CustomerID,
CustomerName,
City,
Country,
PlushType,
PlushPrice
FROM customers cs
LEFT JOIN plushes ps
ON cs.CustomerID = ps.CustomerID
WHERE cs.CustomerID < 4
)
SELECT CustomerID, PlushType, PlushPrice
FROM preferences
In the same way, defined 'dishes' a table containing world famous dishes, the second query retrieve for a another subset of Customers, say second subset, their preferred dish.
WITH foodPreferences
AS
(
SELECT CustomerID,
CustomerName,
City,
Country,
FoodName,
FoodPrice
FROM customers cs
LEFT JOIN foods fs
ON cs.CustomerID = fs.CustomerID
WHERE fs.FoodName = 'pizza'
)
SELECT CustomerID, FoodName
FROM foodPreferences -- it returns customer 6
What I am searching for, is a query that shows customerID, plushType, plushPrice for the customers of the first OR the second subset, i.e. :
That means, I would like to apply the first query to the first OR a second (deriving from another query) subset.
In other words, I want to run the first query for those customers who love pizza.
I am using OracleDB, with PL/Sql language.
Any idea?
P.s. I know that for the written example the structure of the used queries appears weird. Indeed, I am working with something more complex and I preferred to mirror the structure of the query I have
Added this new answer that is more efficient:
with selected_customers (customerid) as (
select customerid
from customers
where customerid < 4
union
select customerid
from customers
left join foods fs on cs.customerid = fs.customerid
where fs.foodname = 'pizza'
)
select customerid, ps.plushtype, ps.plushprice
from selected_customers cs
left join plushes ps on cs.customerid = ps.customerid;
This query will do:
select customerid, plushtype, plushprice
from customers cs
left join plushes ps on cs.customerid = ps.customerid
where customerid in (
select customerid
from customers
where customerid < 4
)
or customerid in (
select customerid
from customers cs
left join foods fs on cs.customerid = fs.customerid
where fs.foodname = 'pizza'
);

Sql distinct selective row after a join question

Let's say i have 2 tables Customer and Books.
Table Books can have multiple rows that pertain to a row in Customer.
Ex:
customer John Doe has an id of 1000.
Table Books has 2 rows with a member_id column with 1000 (John Doe).
These 2 rows are identical EXCEPT one of the fields (book title) is empty. The other row has a value for a title.
Question:
How can i query this so that I retrieve the row with the valid title value, BUT, if both title values are empty, then it just returns a single row?
I certainly hope that made sense.
You should be able to use a distinct operator:
SELECT DISTINCT Customers.member_id, Books.book_title
FROM Customers
INNER JOIN Books ON Customers.member_id = Books.member_id
If that does not work correctly you could use an inner select:
SELECT DISTINCT *
FROM (SELECT Customers.member_id, Books.book_title
FROM Customers
INNER JOIN Books ON Customers.member_id = Books.member_id) As newTable
Also, if this is a frequently used query I would avoid a UNION because they are known to have performance problems.
In response to the edit:
SELECT Customers.member_id, Customer_Info.Name, ISNULL(newTable.book_title, '')
FROM Customers
INNER JOIN Customer_Info
LEFT JOIN (SELECT DISTINCT member_id, book_title FROM Books) newTable
ON newTable.member_ID = Customers.member_id
This should return all books associated with a customer (but only one time for each title and if no books are found then it will return an empty string.) If this does not answer the question please include some additional information about the tables and an example of the result you would like and I will update.
OK, now I think I know what you are looking for:
Here is a possible query based on your original question using the tables provided. However, it will not work if the customer has two distinct e-mail addresses set; in that case, you could add a TOP(1) to ensure only one result but you won't know if it is the "right result."
SELECT Customers.member_id, Office.Office_Name, ISNULL(newTable.email, '')
FROM Customers
INNER JOIN Office
LEFT JOIN (SELECT DISTINCT member_id, email
FROM Books
WHERE email IS NOT NULL AND email <> '') newTable
ON newTable.member_ID = Customers.member_id
Here is another query based on the data you provided and the example output.
SELECT Member_Name, Email
FROM thridTable
WHERE Member_Name = #SomeInputParameter
I'm not sure how representative your sample data is but why would you be storing the member name in more than one table? That is a guaranteed headache in the future.
If I understand what you're saying, this query will return all records with a non-null book title plus all customer records that have no valid book records, valid being defined as a book record with a non-null title.
SELECT c.id, c.name, b.title
FROM customer c
JOIN book b ON c.id = b.customer_id
WHERE b.title IS NOT NULL
UNION ALL
SELECT c.id, c.name, NULL
FROM customer c
WHERE NOT EXISTS (SELECT title FROM book b WHERE customer_id = c.id AND title IS NOT NULL)
You can use:
isnull(BOOKTITLE,'') = ''
on that field and a distinct, and it should give one result