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'
);
Related
I'm doing practice exam material for a distance education course. I have the following three relations (simplified here):
salesperson(emp#, name, salary)
order(order#, cust#, emp#, total)
customer(cust#, name, city)
I'm stuck on a pair of SQL queries.
Display all customer info for customers with at least 1 order.
SELECT * FROM customer
INNER JOIN order ON order.cust# = customer.cust#
GROUP BY cust#;
Display all customer info for customers with at least 2 orders.
SELECT cust#, name, city, industry-type FROM customer
INNER JOIN order ON order.cust# = customer.cust#
GROUP BY cust#
HAVING COUNT(cust#) > 2;
I realize these are misguided attempts resulting from a poor understanding of SQL, but I've spent a ton of time on W3School's SQL Query example tool (https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_where) without getting anywhere, and I finally need some "real" help.
You can try to use subquery to get count by cust# then do inner join to make it.
SELECT c.*
FROM (
SELECT cust# , COUNT(*) cnt
FROM order
GROUP BY cust#
) o INNER JOIN customer c ON c.cust# = o.cust#
WHERE o.cnt > 2
You can change table names according to your DB. Following queries you can directly run in W3Schools
Display all customer info for customers with at least 1 order.
SELECT * FROM customers as cust JOIN orders as o ON o.customerid =
cust.customerid GROUP BY o.customerid;
Display all customer info for customers with at least 2 orders.
SELECT * FROM customers as cust JOIN orders as O ON O.CustomerID = cust.CustomerID GROUP BY cust.CustomerID HAVING COUNT(cust.CustomerID) > 2;
Just learning how to use common table expressions, I wish I was writing like this from the gate.
I've converted all of my queries in my database to a CTE format using WITH ... AS but this one and I am struggling .
So there are two tables:
Table 1. customers
customer_id: unique id for each customer
full_name: customer full name
Table 2. subscriptions
subscription_id: unique id for subscription
customer_id: id for customer who subscribed to subscription
title: name of subscription
The following query is used to return how many subscriptions each of your customers has:
SELECT c.customer_id, c.full_name,
(
SELECT COUNT(*)
FROM subscriptions s
WHERE s.customer_id = c.customer_id
GROUP BY s.customer_id
) subscriptions_count
FROM customers c
How can I rewrite this as a Common Table Expression?
If you really want to use CTE here is one way. You can rewrite it to use left join if you wish to show customers with no counts
with cte as
(select customer_id, count(*) as counts
from subscriptions
group by customer_id)
select c.customer_id, c.full_name, s.counts
from customers c
join cte s on s.customer_id=c.customer_id;
Sure. You can calculate the aggregate first, then join with customers:
WITH cte AS (
SELECT customer_id
, COUNT(*) AS n
FROM subscriptions
GROUP BY customer_id
)
SELECT c.*
, COALESCE(cte.n, 0) AS n
FROM customers AS c
LEFT JOIN cte
ON c.customer_id = cte.customer_id
;
I have three tables:
Carrier(CarrierID(PK), FirstName, LastName)
Customer(CustomerID(PK), FirstName, LastName, RouteID(FK))
Route(RouteID(PK), CarrierID(FK), RouteName)
Each Route only has one carrier.
I need to display the count of customers that each carrier is responsible for.
I know I need to use the CarrierID to get the RouteID, and then use the RouteID to count the rows of Customers with that RouteID.
Can someone explain to me how that SELECT statement would look?
If you need the distinct number of customer you can use count(distinct ..) group by and join
select r.CarrierID, count(distinct CustomerID )
from Route r
inner join Customer c on c.RouteID = r.RouteID
group by r.CarrierID
select r.CarrierID, c2.Firstname, c2.Lastname, count(distinct CustomerID )
from Route r
inner join Customer c on c.RouteID = r.RouteID
inner join Carrier c2 on c2.CarrierID = r.CarrierID
group by r.CarrierID, c2.Firstname, c2.Lastname
I have to 2 queries below which calculate to correct value:
Select Finances.CustomerID,
sum(Finances.Total)Total
from Finances
group by Finances.CustomerID
order by Finances.CustomerID
Select Invoices.CustomerID,
sum(Invoices.InvoiceValue)InvoiceValue
from Invoices
group by Invoices.CustomerID
order by Invoices.CustomerID
within the Finances table a customer can owe money from multiple orders, so for this example lets say the customer has to pay £100+ £400 + £500, which totals to £1000.
the customer then receives the 1st invoice for £100, and pays this..
so the 2nd query would now display £100.... from these 2 values I then want to calculate a 3rd column which deducts the £100 away from the £1000 equalling £900 (the amount left to pay)
the is my table structure:
there are a lot more tables associated however this is where I am the data from with the select statements :)
how would i write the sql statement to do this all together or is it not possible? ideally i would like the to be used within a INSERT -> SELECT -> WHERE NOT EXISTS Statement or alternatively populated in a view. thanks for the help
SAMPLE DATA:
CREATE VIEW CustomerFinances AS
;WITH FinancesCTE AS
(
Select Finances.CustomerID,
sum(Finances.Total)Total
from Finances
group by Finances.CustomerID
),InvoicesCTE AS
(
Select Invoices.CustomerID,
sum(Invoices.InvoiceValue)InvoiceValue
from Invoices
group by Invoices.CustomerID
)
SELECT C.*,
F.Total AS FinanceTotal,
I.InvoiceValue
FROM Customers C
LEFT JOIN FinancesCTE F
ON C.CustomerID = F.CustomerID
LEFT JOIN InvoicesCTE I
ON C.CustomerID = I.CustomerID
GO
Try this,
CREATE VIEW CustomerFinanceDetails AS
(
select c.*,isnull(FinanceTotal,0) as FinanceTotal,isnull(InvoiceTotal,0) as InvoiceTotal
from
(select * from Customers) c
left outer join
(select CustomerID,isnull(SUM(Total),0) as FinanceTotal from Finances group by CustomerID) f on c.CustumerID=f.CustomerID
left outer join
(select CustomerID,isnull(SUM(InvoiceValue),0) as InvoiceTotal from Invoices group by CustomerID) i on c.CustumerID= i.CustomerID
)
Lets say I have the following tables:
Customers
Products
CustomerProducts
Is there a way I can do a select from the Customers and Products tables, where the values are NOT in the map table? Basically I need a matched list of Customers and Products they do NOT own.
Another twist: I need to pair one customer per product. So If 5 customers do not have Product A, only the first customer in the query should have Product A. So the results would look something like this:
(Assume that all customers own product B, And more than one customer owns products A, C, and D)
Customer 1, Product A
Customer 2, Product C
Customer 3, Product D
Final twist: I need to run this query as part of an UPDATE statement in SQL Sever. So I need to take the value from the first row:
Customer 1, Product A
and update the Customer record to something like
UPDATE Customers
SET Customers.UnownedProduct = ProductA
WHERE Customers.CustomerID = Customer1ID
But it would be nice if I could do this whole process, in one SQL statement. So I run the query once, and it updates 1 customer with a product they do not own.
Hope that's not too confusing for you! Thanks in advance!
WITH q AS
(
SELECT c.*, p.id AS Unowned,
ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY c.id) AS rn
FROM Customers c
CROSS JOIN
Products p
LEFT JOIN
CustomerProducts cp
ON cp.customer = c.id
AND cp.product = p.id
WHERE cp.customer IS NULL
)
UPDATE q
SET UnownedProduct = Unowned
WHERE rn = 1
UPDATE statement will update the first customer who doesn't own a certain product.
If you want to select the list, you'll need:
SELECT *
FROM (
SELECT c.*, p.id AS Unowned,
ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY c.id) AS rn
FROM Customers c
CROSS JOIN
Products p
LEFT JOIN
CustomerProducts cp
ON cp.customer = c.id
AND cp.product = p.id
WHERE cp.customer IS NULL
) cpo
WHERE rn = 1
If you update only one customer at once, you might need to remember which products have been assigned automatically (in CustomerProducts) or have a counter how often a product has been assigned automatically (in Products)
I tried this in oracle (hope it works for you too)
UPDATE customers c
SET unownedProduct =
( SELECT MIN( productid )
FROM products
WHERE productid NOT IN (
SELECT unownedProduct
FROM customers
WHERE unownedProduct IS NOT NULL )
AND productid NOT IN (
SELECT productid
FROM customerProducts cp
WHERE cp.customerId = c.customerid )
)
WHERE customerId = 1
What if the customer doesn't own more than one product? and how are you going to maintain this field as the data changes? I thinkyou really need to do some more thinking about your data structure as it doesn't make sense to store this information in the customer table.