How to Properly Write SELECT Statements When Dealing with Multiple Tables - sql

To demonstrate what I am asking, I will present two tables: The Product table and the PC table. The product table contains the following information:
MAKER MODEL TYPE
----- ---------- -------
A 1232 PC
A 1233 PC
A 1276 Printer
A 1298 Laptop
A 1401 Printer
A 1408 Printer
A 1752 Laptop
B 1121 PC
B 1750 Laptop
C 1321 Laptop
D 1288 Printer
D 1433 Printer
E 1260 PC
E 1434 Printer
E 2111 PC
E 2112 PC
The PC table contains the following information:
CODE MODEL SPEED RAM HD CD PRICE
---------- ---------- ---------- ---------- ---------- ---------- ----------
1 1232 500 64 5 12x 600
2 1121 750 128 14 40x 850
3 1233 500 64 5 12x 600
4 1121 600 128 14 40x 850
5 1121 600 128 8 40x 850
6 1233 750 128 20 50x 950
7 1232 500 32 10 12x 400
8 1232 450 64 8 24x 350
9 1232 450 32 10 24x 350
10 1260 500 32 10 12x 350
11 1233 900 128 40 40x 980
12 1233 800 128 20 50x 970
In order to execute a query that returns all PC models, which of the following queries would be better:
SELECT model FROM pc;
OR
SELECT model FROM product JOIN pc USING(model);

Since you only need PC models, the first query you stated will be OK to use.
In your second query, you are getting the product table content first then joining them into PC table, which is slower than your first query and since you do not need any column from Product table, it is not necessary.
You can go with the query below as an alternative, to return only PC related rows, if you do not add the where clause and there is a PC model as 1276. your second query would return the A - 1276 - Printer row.
SELECT DISTINCT model FROM product JOIN pc USING(model) where product.type='PC';

Related

matching customer id value in postgresql

new to learning sql/postgresql and have been hunting all over looking for help with a query to find only the matching id values in a table so i can pull data from another table for a learning project. I have been trying to use the count command, which doesn't seem right, and struggling with group by.
here is my table
id acct_num sales_tot cust_id date_of_purchase
1 9001 1106.10 116 12-Jan-00
2 9002 645.22 125 13-Jan-00
3 9003 1096.18 137 14-Jan-00
4 9004 1482.16 118 15-Jan-00
5 9005 1132.88 141 16-Jan-00
6 9006 482.16 137 17-Jan-00
7 9007 1748.65 147 18-Jan-00
8 9008 3206.29 122 19-Jan-00
9 9009 1184.16 115 20-Jan-00
10 9010 2198.25 133 21-Jan-00
11 9011 769.22 141 22-Jan-00
12 9012 2639.17 117 23-Jan-00
13 9013 546.12 122 24-Jan-00
14 9014 3149.18 116 25-Jan-00
trying to write a simple query to only find matching customer id's, and export them to the query window.

SQL Count for Each Category

I need to count rows based on 2 fields for grouping.
Animals (a)
id group_id strain_id death_date death_cause status
-----------------------------------------------------------------------
1 512 164 2015-12-01 Culled P
2 512 164 2015-12-02 Culled A
3 512 164 2015-12-02 Surplus B
4 512 230 2015-12-06 Culled A
5 512 164 2015-12-28 Culled A
6 512 230 2016-01-20 Culled B
7 512 230 2016-01-20 Surplus P
8 512 164 NULL NULL P
9 512 230 NULL NULL B
10 512 230 NULL NULL A
11 512 164 2016-01-25 Culled B
12 512 164 2016-02-29 Culled A
13 512 230 2016-02-03 Surplus P
14 512 230 2016-02-03 Culled A
Groups (g)
id group_name
--------------
512 Mice
Strain (s)
id strain_name
----------------
164 Strain 1
230 Strain 2
Group Animal Count (gac)
id total_animals alive_count dead_count
----------------------------------------------------------------------
512 14 3 11
Mating History (mh)
id animal_id history_type history_date
--------------------------------------------------------
1001 2 MA 2015-11-20
1002 2 MR 2015-12-01
1003 3 MA 2015-12-01
1004 6 FA 2015-12-21
1005 9 FA 2016-02-07
1006 10 MA 2016-01-27
1007 11 FA 2015-12-12
So when I group them by the strain_id and the death_cause this is what they should look like visually:
Strain 1 ---- Culled
1 512 164 2015-12-01 Culled P
2 512 164 2015-12-02 Culled A
5 512 164 2015-12-28 Culled A
11 512 164 2016-01-25 Culled B
12 512 164 2016-02-29 Culled A
Strain 1 ---- Surplus
3 512 164 2015-12-02 Surplus B
Strain 2 ---- Culled
4 512 230 2015-12-06 Culled A
6 512 230 2016-01-20 Culled B
14 512 230 2016-02-03 Culled A
Strain 2 ---- Surplus
7 512 230 2016-01-20 Surplus P
13 512 230 2016-02-03 Surplus P
What I want to get from the SQL query is the following result:
g_name s_name d_cause a_total c_alive c_dead c_pup c_breeder c_total
------------------------------------------------------------------------------
Mice Strain 1 Culled 12 3 9 1 2 5
Mice Strain 1 Surplus 12 3 9 0 1 1
Mice Strain 2 Culled 12 3 9 0 1 3
Mice Strain 2 Surplus 12 3 9 2 0 2
Basically I want to count the number of animals using 2 categories which in this case is the strain_name and the death_cause
Note that for an animal to be counted as a breeder (c_breeder), I have to look at the Mating History table and check if the animal_id has ever had any of these codes MA or FA.
I am using INNER JOIN on the groups, group_animal_count, and strains. I use LEFT JOIN for mating_history since animals with a status of P won't have records in that table since they're just pups and won't be involved with mating.
Try:
SELECT group_name, strain_name,death_cause, count(*) as Total
FROM ANIMALS a
JOIN GROUPS g ON a.group_id = g.id
JOIN STRAIN s ON a.strain_id = s.id
GROUP BY group_name, strain_name,death_cause
You can do the aggregation before joining the tables:
SELECT group_name, strain_name, death_cause, total
FROM (
SELECT group_id,
strain_id,
death_cause,
COUNT(*) AS total
FROM animals
GROUP BY group_id, strain_id, death_cause
) a
INNER JOIN groups g ON ( g.group_id = a.group_id )
INNER JOIN strain s ON ( s.strain_id = a.strain_id );

Complicated TSQL custom ranking task

I have tried a whole lot of variety of ranking solutions with joins and all to match the needs I want.
Sadly, I cannot come up with correct query to get the desired output.
I am really looking for any help to get explanation that would help me in future with these sort of tasks.
I have the following CTE table contains data values set:
type model price code
Shoes 1298 700,00 1
Shoes 1298 950,00 6
Shoes 1298 1050,00 4
Shoes 1321 970,00 2
Shoes 1750 1200,00 3
Shoes 1752 1150,00 5
Pants 1121 850,00 2
Pants 1121 850,00 4
Pants 1121 850,00 5
Pants 1232 350,00 8
Pants 1232 350,00 9
Pants 1232 400,00 7
Pants 1232 600,00 1
Pants 1233 600,00 3
Pants 1233 950,00 6
Pants 1233 970,00 12
Pants 1233 980,00 11
Pants 1260 350,00 10
Hats 1276 400,00 1
Hats 1288 400,00 6
Hats 1401 150,00 4
Hats 1408 270,00 5
Hats 1433 270,00 2
Hats 1434 290,00 3
Unified records numbering of CTE have to be done in the following manner: first there are the first models of the tables (Shoes, Pants and Hats), then the last models, after that - the second models in the tables, the penultimate, etc. In the case of exhaustion of the models of a particular type, number only remaining models of other types.
Here is the desired output:
Id type model price code
1 Shoes 1298 700.0000 1
2 Pants 1232 600.0000 1
3 Hats 1276 400.0000 1
4 Shoes 1298 950.0000 6
5 Pants 1233 970.0000 12
6 Hats 1288 400.0000 6
7 Shoes 1321 970.0000 2
8 Pants 1121 850.0000 2
9 Hats 1433 270.0000 2
10 Shoes 1752 1150.0000 5
11 Pants 1233 980.0000 11
12 Hats 1408 270.0000 5
13 Shoes 1750 1200.0000 3
14 Pants 1233 600.0000 3
15 Hats 1434 290.0000 3
16 Shoes 1298 1050.0000 4
17 Pants 1260 350.0000 10
18 Hats 1401 150.0000 4
19 Pants 1121 850.0000 4
20 Pants 1232 350.0000 9
21 Pants 1121 850.0000 5
22 Pants 1232 350.0000 8
23 Pants 1233 950.0000 6
24 Pants 1232 400.0000 7
I have updated the desired output (added code column) to better understand the sorting idea. It has to be done in interleaved manner with first coded numbers(i.e. lowest code) of types goes first then the last coded numbers(i.e. highest code) of types goes second, then first coded who's left goes first and then the last coded who's left and etc.
I can not really understand the ordering behind the scene, because the result set is not ordered nor by model nor by code, but here is the idea and you can play with orderings in CTEs:
WITH cte1 AS ( SELECT * ,
ROW_NUMBER() OVER (PARTITION BY type ORDER BY model, code) rn1
FROM #t),
cte2 AS ( SELECT * ,
ROW_NUMBER() OVER (PARTITION BY rn1 ORDER BY
CASE type WHEN 'Shoes' THEN 1
WHEN 'Pants' THEN 2
WHEN 'Hats' THEN 3 END) rn2
FROM cte1 )
SELECT * ,
ROW_NUMBER() OVER (ORDER BY rn1, rn2) rn
FROM cte2
Output:
type model price code rn1 rn2 rn
Shoes 1298 700.00 1 1 1 1
Pants 1121 850.00 2 1 2 2
Hats 1276 400.00 1 1 3 3
Shoes 1298 1050.00 4 2 1 4
Pants 1121 850.00 4 2 2 5
Hats 1288 400.00 6 2 3 6
Shoes 1298 950.00 6 3 1 7
Pants 1121 850.00 5 3 2 8
Hats 1401 150.00 4 3 3 9
Shoes 1321 970.00 2 4 1 10
Pants 1232 600.00 1 4 2 11
Hats 1408 270.00 5 4 3 12
Shoes 1750 1200.00 3 5 1 13
Pants 1232 400.00 7 5 2 14
Hats 1433 270.00 2 5 3 15
Shoes 1752 1150.00 5 6 1 16
Pants 1232 350.00 8 6 2 17
Hats 1434 290.00 3 6 3 18
Pants 1232 350.00 9 7 1 19
Pants 1233 600.00 3 8 1 20
Pants 1233 950.00 6 9 1 21
Pants 1233 980.00 11 10 1 22
Pants 1233 970.00 12 11 1 23
Pants 1260 350.00 10 12 1 24
Rn contains desired values.
You want the value interleaved. Here is how you can do this:
with cte as ( . . . )
select row_number() over (order by seqnum, charindex(type, 'ShoesPantsHats')) as id,
t.*
from (select cte.*,
row_number() over (partition by type order by (select NULL)) as seqnum
from cte
) t
order by seqnum,
charindex(type, 'ShoesPantsHats');
Note the order by clause for row_number(). SQL tables are inherently unordered, and if you care about the ordering of the results within each type, then put the appropriate logic there.
Try this,
with cte as (select type, model,price, ROW_NUMBER() over (partition by type order by type) as rowid from temp)
select * from cte order by rowid, type

how to make Numbering rows in a query

I have a simple select statement:
Get numbering of rows from Product table in the following order: a name of the manufacturer in
--decreasing order of quantity of models produced by it (when there is identical quantity of models
--for a number of manufacturers, their names should follow in increasing alphabetic order), model (increasing order).
--Output: number in accordance with the above order, a name of the manufacturer (maker), model
RESULT SHOULD BE -
no maker model
1 A 1232
10 E 2112
11 E 2113
12 B 1121
13 B 1750
14 D 1288
15 D 1433
16 C 1321
2 A 1233
3 A 1276
4 A 1298
5 A 1401
6 A 1408
7 A 1752
8 E 1260
9 E 1434
MY QUERY :
with result as
(select *, count(*) over (partition by maker) as ModelsCount from Product)
select row_number() over (order by ModelsCount desc,model) AS No, Maker, Model
from result
MY RESULT:
no maker model
1 A 1232
10 E 2112
11 E 2113
12 B 1121
13 D 1288
14 D 1433
15 B 1750
16 C 1321
2 A 1233
3 A 1276
4 A 1298
5 A 1401
6 A 1408
7 A 1752
8 E 1260
9 E 1434

Point out the maker and speed of the laptops having hard drive capacity more or equal to 10 Gb

I tried this in two ways (I think they are the same):
select product.maker,speed from product,laptop
where product.model=laptop.model and hd>='10'
and
select product.maker, speed from laptop
join product
on (product.model=laptop.model)
where hd>='10'
and I receive this in the simulator:
"Your query produced correct result set on main database, but it failed test on second, checking database. * Wrong number of records (more by 1)
This exercise has FAQ"
The relevant tables are:
Table Laptop
code model speed ram hd price screen
------------------------------------------------------
1 1298 350 32 4.0 700.0000 11
2 1321 500 64 8.0 970.0000 12
3 1750 750 128 12.0 1200.0000 14
4 1298 600 64 10.0 1050.0000 15
5 1752 750 128 10.0 1150.0000 14
6 1298 450 64 10.0 950.0000 12
Table Product:
maker model Type
-----------------------
A 1232 PC
A 1233 PC
A 1276 Printer
A 1298 Laptop
A 1401 Printer
A 1408 Printer
A 1752 Laptop
B 1121 PC
B 1750 Laptop
C 1321 Laptop
D 1288 Printer
D 1433 Printer
E 1260 PC
E 1434 Printer
E 2112 PC
E 2113 PC
When this answer was written, one query used hd>=10 and one used hd>='10'. The query has since been edited.
When you use the '10' in the comparison, you cause the DBMS to do the comparison as a string instead of as a number. Under string comparison, 9 is greater than 10.
As a general rule of thumb, if the data column is a string type, you should compare it with a string: if the column is numeric type, you should compare it with plain numbers (not with strings). Note that different DBMS may have different ways of interpreting a mixed-type expression.
select distinct product.maker, speed from laptop
join product
on (product.model=laptop.model)
where hd>='10'
or
select distinct product.maker,speed from product,laptop
where product.model=laptop.model and hd>='10'
Select P.maker, L.speed
from Laptop L, Product P
where P.model =L.model
And L.hd > = 10
Group by P.maker, L.speed
Try to use group by statement to get the correct solution.
Select distinct Product.maker,Laptop.speed from Product,Laptop where Product.model=Laptop.model and Laptop.hd>=10 and type='laptop'
select DISTINCT maker, speed
from Product
join Laptop on (Product.model=Laptop.model)
where hd >= 10
order by speed asc
You forgot to filter for the laptops:
SELECT Product.maker, Laptop.speed
FROM Product INNER JOIN Laptop ON Laptop.model = Product.model
WHERE Laptop.hd >= 10 AND Product.type = 'Laptop'
Use keyword Distinct before product.maker.