DVD rental SQL ###### QUERY - sql

Trying to find how many active or inactive rentals there are for a specific store. 1 = active, 0 = inactive. the answer I get doubles the amount of customers and is not right. Can anyone help
SELECT COUNT(*)
FROM customer, store
WHERE active = 0
AND store_id = 2
ORDER BY customer_id;

The join is incorrect. There are no join criteria specified so the result is all possible combinations of customers and stores, filtered by where clause.
Correct way to join is:
...
from customer inner join store on store.store_id = customer.store_id
...
(assuming customer table has the store_id field).
And you probably want to group by store using the group by clause.

Related

Showing customers who have purchased more than 1 product, but from the same subscription

I'm trying to find the number of customers who have ordered more than one product, with the same subscription.
I've first selected the count of the id_customer from customer. Then joined on subscription and order (on the correct keys). This was done so that I have all the data available to me from all 3 tables. Then grouped by the id_customer to get just the unique customers. And lastly filtered to have a fk_product (products a customer has) greater than 1.
SELECT COUNT(t1.id_customer)
FROM customer t1
INNER JOIN subscription t2 ON t1.id_customer = t2.fk_customer
INNER JOIN order t3 ON t2.id_subscription = t3.fk_subscription
GROUP BY t1.id_customer
HAVING COUNT(t3.fk_product) > 1
I'd like to better understand if this is the correct syntax to obtain the data I'm looking for. Since I have t2.id_subscription and t3.fk_subscription linked, wouldn't this be correct? I'm still getting the wrong output. I'm thinking its perhaps the way I have my scopes, or some subtle aspect of SQL that I'm not using/understanding.
Thank you for your help!!
Use two levels of aggregation. Your data model is a bit hard to follow, but I think:
SELECT COUNT(DISTINCT so.fk_customer)
FROM (SELECT s.fk_customer, s.id_subscription
FROM subscription s
order o
ON s.id_subscription = o.fk_subscription
GROUP BY s.fk_customer, s.id_subscription
HAVING MIN(o.fk_product) <> MAX(o.fk_product)
) so
select count(distinct s.id_customer)
from (
SELECT t1.id_customer
FROM customer t1
INNER JOIN subscription t2 ON t1.id_customer = t2.fk_customer
INNER JOIN order t3 ON t2.id_subscription = t3.fk_subscription
GROUP BY t1.id_customer, t3.fk_subscription
HAVING COUNT(1) > 1
) s

stacking data from two tables with different dates

I have two tables, Sales and Returns. They have CustomerID, ProductCode, Name, SalesDate, SalesWeek, SalesAmount and ReturnsDate, ReturnsWeek, ReturnsAmount. What I really want to do is just join these tables and stack them on top of each other so the client has data in a single report for both sales and returns.
Sales and Returns dates are different but the product code, customer ID and Name can be same for a record in output table. For instance Customer A bought a product last month and returned it next month, so his record can appear in returns table.
To achieve this I have tried using union by selecting all columns between both tables but I am getting a mix of records for sales and returns with no consistency. All I want to do is see Nulls for Customers who have no business with Returns and vice versa. I was thinking Left Join in this case should work but it isn't working. So I am seeing mixed up data in all columns for Sales and Returns amounts. Attached is the picture that has two tables, the output I am seeing and the out put I want to see. Also I am performing Weekly aggregations for Sales and Returns amounts. What is the best and easiest way to achieve this ? I am sorry I may have not structured my question properly but the image might help #NewToSQL
Presumably, a customer can purchase a given product more than once. If so, a full join is the right solution, but you need a bit more logic to ensure non-duplication in the results:
select . . .
from (select s.*,
row_number() over (partition by product_code, customer_id order by (select NULL)) as seqnum
from sales s
) s full join
(select r.*,
row_number() over (partition by product_code, customer_id order by (select NULL)) as seqnum
from returns r
) r
on s.product_code = r.product_code and s.customer_id = r.customer_id;
I am leaving the name out, because I assume it is defined by the customer id.
You need to do a FULL JOIN sales table with returns table on those columns that you mentioned.
Something like :
SELECT *
FROM sales s
FULL JOIN returns r
ON s.product_code = r.product_code
AND s.customerid = r.customer_id

Excluding multiple results in specific column (SQL JOIN)

I'm taking my first steps in terms of practical SQL use in real life.
I have a few tables with contractual and financial information and the query works exactly as I need - to a certain point. It looks more or less like that:
SELECT /some columns/ from CONTRACTS
Linked 3 extra tables with INNER JOIN to add things like department names, product information etc. This all works but they all have simplish one-to-one relationship (one contract related to single department in Department table, one product information entry in the corresponding table etc).
Now this is my challenge:
I also need to add contract invoicing information doing something like:
inner join INVOICES on CONTRACTS.contnoC = INVOICES.contnoI
(and selecting also the Invoice number linked to the Contract number, although that's partly optional)
The problem I'm facing is that unlike with other tables where there's always one-to-one relationship when joining tables, INVOICES table can have multiple (or none at all) entries that correspond to a single contract no. The result is that I will get multiple query results for a single contract no (with different invoice numbers presented), needlessly crowding the query results.
Essentially I'm looking to add INVOICES table to a query to just identify if the contract no is present in the INVOICES table (contract has been invoiced or not). Invoice number itself could be presented (it is with INNER JOIN), however it's not critical as long it's somehow marked. Invoice number fields remains blank in the result with the INNER JOIN function, which is also necessary (i.e. to have the row presented even if the match is not found in INVOICES table).
SELECT DISTINCT would look to do what I need, but I seemed to face the problem that I need to levy DISTINCT criteria only for column representing contract numbers, NOT any other column (there can be same values presented, but all those should be presented).
Unfortunately I'm not totally aware of what database system I am using.
Seems like the question is still getting some attention and in an effort to provide some explanation here are a few techniques.
If you just want any contract with details from the 1 to 1 tables you can do it similarily to what you have described. the key being NOT to include any column from Invoices table in the column list.
SELECT
DISTINCT Contract, Department, ProductId .....(nothing from Invoices Table!!!)
FROM
Contracts c
INNER JOIN Departments D
ON c.departmentId = d.Department
INNER JOIN Product p
ON c.ProductId = p.ProductId
INNER JOIN Invoices i
ON c.contnoC = i.contnoI
Perhaps a Little cleaner would be to use IN or EXISTS like so:
SELECT
Contract, Department, ProductId .....(nothing from Invoices Table!!!)
FROM
Contracts c
INNER JOIN Departments D
ON c.departmentId = d.Department
INNER JOIN Product p
ON c.ProductId = p.ProductId
WHERE
EXISTS (SELECT 1 FROM Invoices i WHERE i.contnoI = c.contnoC )
SELECT
Contract, Department, ProductId .....(nothing from Invoices Table!!!)
FROM
Contracts c
INNER JOIN Departments D
ON c.departmentId = d.Department
INNER JOIN Product p
ON c.ProductId = p.ProductId
WHERE
contnoC IN (SELECT contnoI FROM Invoices)
Don't use IN if the SELECT ... list can return a NULL!!!
If you Actually want all of the contracts and just know if a contract has been invoiced you can use aggregation and a case expression:
SELECT
Contract, Department, ProductId, CASE WHEN COUNT(i.contnoI) = 0 THEN 0 ELSE 1 END as Invoiced
FROM
Contracts c
INNER JOIN Departments D
ON c.departmentId = d.Department
INNER JOIN Product p
ON c.ProductId = p.ProductId
LEFT JOIN Invoices i
ON c.contnoC = i.contnoI
GROUP BY
Contract, Department, ProductId
Then if you actually want to return details about a particular invoice you can use a technique similar to that of cybercentic87 if your RDBMS supports or you could use a calculated column with TOP or LIMIT depending on your system.
SELECT
Contract, Department, ProductId, (SELECT TOP 1 InvoiceNo FROM invoices i WHERE c.contnoC = i.contnoI ORDER BY CreateDate DESC) as LastestInvoiceNo
FROM
Contracts c
INNER JOIN Departments D
ON c.departmentId = d.Department
INNER JOIN Product p
ON c.ProductId = p.ProductId
GROUP BY
Contract, Department, ProductId
I would do it this way:
with mainquery as(
<<here goes you main query>>
),
invoices_rn as(
select *,
ROW_NUMBER() OVER (PARTITION BY contnoI order by
<<some column to decide which invoice you want to take eg. date>>) as rn
)
invoices as (
select * from invoices_rn where rn = 1
)
select * from mainquery
left join invoices i on contnoC = i.contnoI
This gives you an ability to get all of the invoice details to your query, also it gives you full control of which invoice you want see in your main query. Please read more about CTEs; they are pretty handy and much easier to understand / read than nested selects.
I still don't know what database you are using. If ROW_NUMBER is not available, I will figure out something else :)
Also with a left join you should use COALESCE function for example:
COALESCE(i.invoice_number,'0')
Of course this gives you some more possibilities, you could for example in your main select do:
CASE WHEN i.invoicenumber is null then 'NOT INVOICED'
else 'INVOICED'
END as isInvoiced
You can use
SELECT ..., invoiced = 'YES' ... where exists ...
union
SELECT ..., invoiced = 'NO' ... where not exists ...
or you can use a column like "invoiced" with a subquery into invoices to set it's value depending on whether you get a hit or not

Access 2002 SQL for joining three tables

I have been trying to get this to work for a while now. I have 3 tables. First table has the Sales for customers which include the CustomerID, DateOfSales (Which always has the first of the month). The second table has the CustomerName, CustomerID. The third table has which customers buy what product lines. They are stored by CustomerID, ProductID.
I want to get a list (from one SQL hopefully) that has ALL the customers that are listed as buying a certain ProductID AND the maxDate from the Sales. I can get all of them IF there are sales for that customer. How the heck do I get ALL customers that buy the certain ProductID AND the maxDate from Sales or NULL if there is no sales found?
SalesList |CustomerList|WhoBuysWhat
----------|------------|-----------
maxDate |CustomerID |CustomerID
CustomerID| |ProductID=17
This is as close as I got. It gets all max dates but only if there have been sales. I want the CustomerID and a NULL for the maxDate if there were no sales recorded yet.
SELECT WhoBuysWhat.CustomerID, CustomerList.CustomerName,
Max(SalesList.MonthYear) AS MaxOfMonthYear FROM (CustomerList INNER
JOIN SalesList ON CustomerList.CustomerID = SalesList.CustomerID) INNER
JOIN WhoBuysWhat ON CustomerList.CustomerID = WhoBuysWhat.CustomerID
WHERE (((SalesList.ProductID)=17)) GROUP BY WhoBuysWhat.CustomerID,
CustomerList.CustomerName;
Is it possible or do I need to use multiple SQL statements? I know we should get something newer than Access 2002 but that is what they have.
You want LEFT JOINs:
SELECT cl.CustomerID, cl.CustomerName,
Max(sl.MonthYear) AS MaxOfMonthYear
FROM (CustomerList as cl LEFT JOIN
(SELECT sl.*
FROM SalesList sl
WHERE sl.ProductID = 17
) as sl
ON cl.CustomerID = sl.CustomerID
) LEFT JOIN
WhoBuysWhat wbw
ON cl.CustomerID = wbw.CustomerID
GROUP BY cl.CustomerID, cl.CustomerName;

Count query results on multi-join statements

select cnt.loginid, grp.last_name as 'Group Name'
from contact cnt
right join grpmem list on cnt.contact_uuid = list.member
left join contact grp on grp.contact_uuid = list.group_id
join contact_acctyp cntacc on cnt.contact_uuid = cntacc.contact_uuid
where cntacc.c_acctyp_id in (select id from acctyp_v2 where sym like 'CDN%')
I have written a query for our system that pulls a list of all Canadian contacts and the group they are in.
Now, for people who are in multiple groups (their loginid appears multiple times) I need to determine the number of groups they are in (return a count). However, I am unsure of how to perform the count.
I'd like my output to be in the following format:
| USER ID | # of Groups |
I can't seem to figure out how to turn what I've written into that.
Assuming all you want to do is aggregate the information you are already getting back, and without looking in detail at your query, here is a guess:
select
cnt.loginid,
COUNT(*)
from contact cnt
right join grpmem list on cnt.contact_uuid = list.member
left join contact grp on grp.contact_uuid = list.group_id
join contact_acctyp cntacc on cnt.contact_uuid = cntacc.contact_uuid
where cntacc.c_acctyp_id in (select id from acctyp_v2 where sym like 'CDN%')
GROUP BY
cnt.loginid