Writing a Query with Distinct Count in Access - sql

I'm having some difficulty with a query that I'm writing that is meant to display the "makers" that produce laptops with 3 or more DIFFERENT speeds.
SELECT DISTINCT Product.maker, Count(Laptop.speed) AS [3+ Different Speeds]
FROM Laptop INNER JOIN Product ON Laptop.model = Product.model
WHERE type = "laptop"
GROUP BY Product.maker
HAVING Count(*) >= 3;
This gives me the 2 correct "makers" that produce 3 or more laptop models, however, one "maker", A, produces two laptop models with the SAME speed, so that "maker" needs to be eliminated from the resulting table, which is below.
maker 3+ Different Speeds
A 3
E 3
Here's the Laptop table where the model and speed data is stored:
model speed
2001 2.00 E
2002 1.73 E
2003 1.80 E
2004 2.00 A
2005 2.16 A
2006 2.00 A
E produces the top 3, and A produces the bottom 3. I'm fairly certain that I need to make my Count function DISTINCT, however, I know that Access does not support DISTINCT Count. Any assistance/suggestions would be greatly appreciated!

The below query should solve your problem.
SELECT
maker,
COUNT(speed)
FROM(
SELECT
p.maker,
l.speed
FROM
Laptop l
INNER JOIN Product p
ON l.model = p.model
WHERE
type = "laptop"
GROUP BY 1,2
) foo
GROUP BY 1
HAVING COUNT(1) >= 3
First you aggregate all speeds for the same maker, so the inner query would produce:
maker | speed | count
-------+-------+-------
E | 1.73 | 1
E | 1.80 | 1
A | 2.16 | 1
E | 2.00 | 1
A | 2.00 | 2
Now you have distinct rows for each pair (maker, speed) so that you can simply run a COUNT() over speed.
Result
maker | count
-------+-------
E | 3
A | 2
Now eliminate A with HAVING clause.

Your query will work fine if you take out the distinct keyword. If you only group by the maker, then that query will bring you back only one record per maker, the distinct is actually redundant.

This is the WORKING query that I came up with, a slightly modified version of what you provided me with.
SELECT P.maker AS [Maker], Count(L.speed) AS [3+ Different Speeds]
FROM (SELECT P.maker, L.speed FROM Laptop AS L INNER JOIN Product AS P ON L.model = P.model
WHERE type = "laptop"
GROUP BY P.maker, L.speed)
GROUP BY [Maker]
HAVING Count(L.speed) >= 3;
Thanks again!

Related

Operation along the same column given a condition

I have a list of amounts I want to add up for a particular currency code and display that total along with the underlying currency.
SOURCE TABLE TRANS
PORTCODE
AMOUNT
CCYTYPE
CCYCODE
BC100
40
DAC
DAC
BC100
30
DAC
DAC
BC100
30
DAC
DAC
BC100
35
ROPE
EUR
BC100
25
ROPE
EUR
BC100
25
ROPE
EUR
For example:
Select CCYCODE
FROM TRANS
WHEN CCYTYPE='ROPE'
OUTPUT
EUR
However, I am also using the CCYTYPE='DAC' to perform a calculation such as:
SELECT
T.PORTCODE,
T.ID,
T.VAN = sum(amount)
FROM TRANS T
INNER JOIN METRIC M
ON T.METRICCODE=M.METRICCODE
WHERE 1=1
AND T.CCYTYPE='DAC'
The sum is comprised of several hundred amounts in the TRANS table.
OUTPUT
PORTCODE | ID | VAN | CCYCODE
BC100 | 31 | 100 | EUR
How can I get the result of the ccytype, portcode, ID, and VAN to appear together with these two distinct conditions?
The syntax in the two individual queries is incorrect. But assuming it is correct, you can put each individual query in a subquery and join it like it were a table.
Assuming what is common between query 1 and query 2 is PORTCODE you can do the following:
SELECT
a.*
,b.CCYCODE
FROM
(SELECT
T.PORTCODE,
T.ID,
sum(amount) AS VAN
FROM TRANS T
INNER JOIN METRIC M
ON T.METRICCODE=M.METRICCODE
WHERE
1=1
AND T.CCYTYPE='DAC'
GROUP BY
T.PORTCODE,
T.ID
) AS a
LEFT JOIN
(Select
PORTCODE
,CCYCODE
FROM TRANS
WHEN CCYTYPE='ROPE'
) AS b
ON a.PORTCODE = b.PORTCODE

Postgresql Joining tables without losing records

Let's say I have the following tables:
1 - StartingStock:
vendor | starting_stock
------------------------
adidas | 13
Reebok | 5
2 - Restock:
vendor | restocks
-----------------
adidas | 2
nike | 3
3 - Sales:
vendor | quantity_sold
----------------------
adidas | 10
nike | 1
I want my resulting table to be the sell through grouped by vendor. In this scenario, sell through is calculated like this: quantity_sold/(starting_stock + restocks). My only problem is that starting stock and restock tables may not have the some vendors that are present in the sales table. So in the scenario above, StartingStock does not have nike as a record. So if that's the case the sell though for nike would be just 1/3 or 1/(3+0). Therefore, my resulting table would be:
vendor | sell_through
---------------------
adidas | 1.5
nike | 0.33
Reebok | 0
So I'd want all of the vendors present in the result table (if it has no sales, value is 0 like Reebok shown above).
I tried working with the different types of joins but I couldn't get it. Any help would be great. Thanks.
We can try a full outer join approach here:
SELECT
COALESCE(ss.vendor, r.vendor, s.vendor) AS vendor,
COALESCE(s.quantity_sold, 0) /
(COALESCE(ss.starting_stock, 0) + COALESCE(r.restocks, 0)) AS sell_through
FROM StartingStock ss
FULL OUTER JOIN Restock r ON ss.vendor = r.vendor
FULL OUTER JOIN Sales s ON s.vendor = COALESCE(ss.vendor, r.vendor)
Demo
Note that I am coming up with 2/3 for the sell through for Adidas, since the quantity sold is 10, and the sum of stocks is 15.
I would use union all and aggregation:
select vendor,
sum(starting_stock), sum(restock), sum(quantity_sold),
(sum(quantity_sold) * 1.0 / sum(starting_stock) + sum(restock)) as sell_through
from ((select vendor, starting_stock, 0 as restock, 0 as quantity_sold
from startingstock
) union all
(select vendor, 0 as starting_stock, restock, 0 as quantity_sold
from restock
) union all
(select vendor, 0 as starting_stock, 0 as restock, quantity_sold
from sales
)
) v
group by vendor;
In particular, this version includes each number in the calculation only once. A JOIN approach will produce inaccurate results if a vendor has multiple rows in any of the tables.

SELECT with LEFT JOIN performing math operation twice?

The general idea of what I'm trying to do is this:
Select all planned prices for an order, then subtract from that total all actual prices on that order.
The planned price and actual price are on different tables. When I have a single planned price and a single actual price, this works fine. However, when I have multiple planned prices or multiple actual prices it is giving me odd results as if the algebra is happening multiple times.
Query:
SELECT PL.orderid, (SUM(PL.lineprice) - NVL(SUM(AC.lineprice),0)) AS
Difference FROM plans PL
LEFT JOIN actuals AC ON PL.orderid = AC.orderid
WHERE PL.customer IN (SELECT customer FROM ...)
GROUP BY PL.orderid
ORDER BY PL.orderid;
The results of the query:
Orderid Difference
X-1224 100
X-1226 80
X-1345 70000
X-1351 125000
X-1352 10000
Y-2403 190000
My Plan table looks like this:
Orderid Planned_Price
X-1224 100
X-1226 100
X-1345 105000
X-1351 100000
X-1352 10000
X-1352 50000
Y-2403 25000
Y-2403 100000
And my Actual table this:
Orderid Actual_Price
X-1226 20
X-1345 35000
X-1351 25000
X-1351 50000
X-1352 25000
Y-2403 25000
Y-2403 5000
So it seems to work when I have only a single row in each table, or a single row in plans and no rows in actuals i.e., X-1224, X-1226 and X-1345.
However the results are too high or too low when I have multiple rows, with the same OrderID, in either table i.e., all the rest
I'm stumped as to why this is the case. Any insights are appreciated.
edit: Results I'd like, taking Y-2403 as example: (25000 + 100000) - (25000 + 5000) = 95000. What I'm getting is double that at 190000.
Why is this the case?
Because that is how join works. If you have data like this:
a
1
1
2
2
And b:
b
1
1
1
2
Then the result of a join will have six "1"s and two "2"s.
Your question doesn't say what you want for results, but a typical approach is to aggregate before doing the joins.
EDIT:
You seem to want:
select p.orderid,
(p.lineprice - coalesce(lineprice, 0)) as Difference
from (select orderid, sum(lineprice) as lineprice
from plans p
group by orderid
) p left join
(select orderid, sum(lineprice) as lineprice
from actuals a
group by orderid
) a
on p.orderid = a.orderid
where p.customer in (SELECT customer FROM ...)
order by p.orderid;
I suppose you are looking to compare the summed_up_prices by order id of plan table with the summed_up prices by order id actual plan table.?
If so the following can be done to ensure there are no duplicates entries by order
select a.orderid
,NVL(max(b.summed_up),0) - sum(a.actual_price) as difference
from actual_table a
left join (select pt.orderid
,sum(pt.planned_price) as summed_up
from planned_table pt
group by pt.orderid
)b
on a.orderid=b.orderid
group by a.orderid
+---------+------------+
| ORDERID | DIFFERENCE |
+---------+------------+
| X-1226 | 80 |
| Y-2403 | 95000 |
| X-1351 | 25000 |
| X-1345 | 70000 |
| X-1352 | 35000 |
+---------+------------+
Here is the dbfiddle link with the data
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=3cacffd19b39ecaf7ad752dff262ac47

SQL How can this happen? - Query which normally returns 1 result alone actually resulted in multiple results when put inside WHERE clause

Question brief
I'm doing this practice on w3resource and I couldn't understand why the solution worked. I'm 2 days old to SQL. I'll appreciate very much if someone can help me explain.
I have 2 tables, COMPANY(com_id, com_name) and PRODUCT(pro_name, pro_price, com_id). Each company has several products with different prices. Now I need to write a query to display companies' name together with their most expensive products respectively.
The sample answer on the practice is like this
SELECT c.com_name, p.pro_name, p.pro_price
FROM product p
INNER JOIN company c ON p.com_id = c.com_id
AND p.pro_price =
( SELECT MAX(p.pro_price)
FROM product p
WHERE p.com_id = c.com_id );
The query returned expected result.
com_name pro_name pro_price
--------- --------- -----------
Samsung Monitor 5000.00
iBall DVD drive 900.00
Epsion Printer 2600.00
Zebronics ZIP drive 250.00
Asus Mother Board 3200.00
Frontech Speaker 550.00
But I cannot understand how, especially the part inside the bottom sub-query. Isn't SELECT MAX(p.pro_price) supposed to return only 1 highest price of all companies together?
I also tried subsecting this sub-query like this
SELECT MAX(p.pro_price)
FROM product p
INNER JOIN company c ON p.com_id = c.com_id
WHERE p.com_id = c.com_id;
... and it only returned 1 maximum value.
max(p.pro_price)
-----
5000.00
So how does the final result of the whole query include more than 1 records? There's no GROUP BY or anything.
By the way, the query seemed to use 2 conditions for INNER JOIN. But I also tried swapping the 2nd condition into a WHERE clause and it still worked the same. This is one more thing I don't understand.
The databases involved
COMPANY table
COM_ID | COM_NAME
----------------
11 | Samsung
12 | iBall
13 | Epsion
14 | Zebronics
15 | Asus
16 | Frontech
PRODUCT table
PRO_NAME PRO_PRICE COM_ID
-------------------- ---------- ---------
Mother Board 3200 15
Key Board 450 16
ZIP drive 250 14
Speaker 550 16
Monitor 5000 11
DVD drive 900 12
CD drive 800 12
Printer 2600 13
Refill cartridge 350 13
Mouse 250 12
The sub-query is a correlated sub-query. This query is executed for each value of c.com_id in the outer query:
WHERE p.com_id = c.com_id

Average of rows with different column values

2 tables
Product(maker, model)
PC(model, ..., price)
model is a foreign key between Product and PC
I need to select all rows in Product that have the same maker and average their price.
Therefore with these tables:
Product PC
------- -------
A 1 1 60
A 2 2 80
B 3 3 110
B 4 4 140
I should get:
maker avg(price)
---------------------
A 70
B 125
I have tried this, but have no idea how to combine the rows and average just those that get combined. This displays the average across the entire PC table for all maker.
select
Product.maker, Product.model, avg(PC.price)
from
Product, PC
group by
Product.maker, Product.model
order by
maker asc;
Don't use the old legacy implicit join syntax any more. Use explicit joins
select Product.maker, avg(PC.price)
from Product
left join PC on PC.model = Product.model
group by Product.maker
order by Product.maker asc