Cross Join with Filter? - sql

i need to make Sp to distribute students to their sections
the procedure take 2 string parameters StuID and SecID
in case I've send '1,2,3,4,5' as StuID and 'a,b' as SecID
i'm using spliting function which well return tables
Tb1 | Tb2
1 | a
2 | b
3 |
4 |
5 |
how can i get the following result
1 a
2 b
3 a
4 b
5 a
....
I've tried to do it via cross join but it did not show the result i want
select US.vItem as UserID,SE.vItem as Section
from split(#pUserID,',') us
cross join split(#pSectionID,',') se

Cross join isn't meant to work like that.
This will give you the results you want, but it's a bodge.
select t1.vItem, t2.VItem from
( select *, ROW_NUMBER() over (order by vItem) r from US ) t1
inner join
( select *, ROW_NUMBER() over (order by vItem desc) -1 r from SE ) t2
on t2.r = t1.r % (select COUNT(*) from SE)
order by t1.vItem

Related

join two sql table as column

i have two tables as below:
firsttable
id
cat_id
name
1
2
name_01
2
2
name_02
3
1
name_03
4
3
name_04
5
3
name_04
secondtable
id
name
1
cat_01
2
cat_02
3
cat_03
my question is how can i create below table result?
id(secondtable)
name(secondtable)
count(firsttable)
1
cat_01
1
2
cat_02
2
3
cat_03
2
select t2.id,t2.name,
(select count(*) from firsttable t1 where t1.cat_id=t2.id )as count
from secendtable t2;
Just using standard aggregation
select
s.id,
s.name,
count(*)
from firsttable f
join secondtable s
on f.cat_id = s.id
group by s.id, s.name order by s.id
It's very Simple like that
SELECT s.id,s.name, (SELECT count(*)
FROM `firsttable` AS f
WHERE f.cat_id = s.id ) as count
FROM `secondtable` AS s

Find the percentage of a group by count row in sql

I have a table as
Person| Count
A | 10
B | 20
C | 30
I use code as below to get above table:
select new_table.person, count(new_table.person)
from (person_table_1
inner join person_table_2
on person_table_1.user_name = person_table_2.user_all_name) new_table
group by new_table.person
However, I wish to have the percentage for each row based on overall sum in count.
Expected:
Person| Count | Percentage
A | 10 | 0.167
B | 20 | 0.333
C | 30 | 0.500
I wish it to be in 3 decimal places. Can anyome please help me. thank you.
Just do an inner query in SELECT clause
select p1.person, count(p1.person), count(p1.person) / (SELECT COUNT(p2.person) FROM person_table p2)
from person_table p1
group by p1.person
Edit: if you want only up to 3 decimal:
select
p1.person,
count(p1.person),
ROUND(count(p1.person) / (SELECT COUNT(p2.person) FROM person_table p2), 3)
from person_table p1
group by p1.person
Edit 2: OP edited his/her table
select
new_table.person,
count(new_table.person),
ROUND(
count(new_table.person) /
SELECT COUNT(new_table_COUNTER.person) FROM (
person_table_1
inner join person_table_2
on person_table_1.user_name = person_table_2.user_all_name
) new_table_COUNTER )
from
(
person_table_1
inner join person_table_2
on person_table_1.user_name = person_table_2.user_all_name
) new_table
group by new_table.person
Try below query:
declare #tbl table ([person] varchar(5));
insert into #tbl values
('a'),('a'),('a'),('b'),('b'),('c');
-- here we tabke max(rowsCnt), but we wwant any value, because every value is the same in that column
select person, count(*) * 1.0 / max(rowsCnt) [percentage] from (
select person,
count(*) over (partition by (select null)) rowsCnt
from #tbl
) a group by person

How do I join two tables in SQL limiting the second table data depending on the first one?

I have two tables looking something like this:
IMP DATE CAT
A 03/03/2016 1
B 04/04/2016 1
C 09/09/2016 2
D 01/01/2017 1
E 02/02/2017 1
F 03/03/2017 2
G 04/04/2017 2
===================
EXP DATE CAT
H 01/01/2016 1
I 05/05/2016 1
J 07/07/2016 2
K 11/11/2016 2
L 01/01/2017 1
M 03/03/2017 1
N 04/04/2017 2
O 05/05/2017 2
I want to join the first table to the second one but limit the lines joined from the second table by the latest date on the first table (per category).
The result I'm looking for would be every row in both tables except Item "M" (because Cat 1 in Table 1 has a latest date of February) and Item "O" (because Cat 2 in Table 1 has a latest date of April).
I've tried conditionalds within a where clause in the 2nd table but haven't got far.
Is there a simple way to do this? Any help is appreciated. I'm using SQL Server 2008 by the way.
Your description of the problem is specifically about using join. That suggests a query like this:
select . . .
from (select t1.*, max(t1.date) over (partition by t1.cat) as maxdate
from table1 t1
) t1 join
table2 t2
on t1.cat = t2.cat and t2.date <= t1.maxdate;
Desire output and its format is still not clear.
are you looking for this ?
;With CTE as
(
select *, row_number()over(partition by cat order by DATEs desc) rn
from #table1
)
--select * from cte
--where rn=1
select * from cte t1
left join #table2 t2
on t1.CAT=t2.CAT and t2.DATEs<=t1.DATEs
where rn=1

Join a dynamic number of rows in postgres

Let's say I have the following tables:
Batch Items
---+----- ---+----------+--------
id | size id | batch_id | quality
---+----- ---+----------+--------
1 | 10 1 | 1 | 9
2 | 2 2 | 1 | 10
3 | 2 | 1
4 | 2 | 2
5 | 2 | 1
6 | 2 | 9
I have batches of items. They are sent by batches of size batch.size. An item is broken if it's quality is <= 3.
I want to know the number of broken items in the last batches sent:
batch_id | broken_item_count
---------+---------------------
1 | 0
2 | 2 (and not 3)
My idea is the following:
SELECT batch.id as batch_id, COUNT(broken_items.*) as broken_item_count
FROM batch
INNER JOIN (
SELECT id
FROM items
WHERE items.quality <= 3
ORDER BY items.id asc
LIMIT batch.size -- invalid reference to FROM-clause entry for table "batch"
) broken_items ON broken_items.batch_id = batch.id
(I would ORDER BY items.shipped_at. But for simplicity, I order by items.id)
But this query shows me the error I put as the comment.
How can I limit the number of joined items based on the batch.size that is different for each row ?
Is there any other way to achieve what I want ?
SELECT b.id AS batch_id
, count(i.quality < 4 OR NULL) AS broken_item_count
FROM batch b
LEFT JOIN (
SELECT batch_id, quality
, row_number() OVER (PARTITION BY batch_id ORDER BY id DESC) AS rn
FROM items
) i ON i.batch_id = b.id
AND i.rn <= b.size
GROUP BY 1
ORDER BY 1;
SQL Fiddle with added examples.
This is much like #Clodoaldos's answer, but with a couple of differences. Most importantly:
You want to count the broken items in the last batches sent, so we have to ORDER BY id DESC
If there can be batches without items at all you need to use LEFT JOIN instead of a plain JOIN or those batches are excluded.
Consequently, the check i.rn <= b.size needs to move from the WHERE clause to the JOIN clause.
SQL Fiddle
select
b.id as batch_id,
count(quality <= 3 or null) as broken_item_count
from
batch b
inner join (
select
id, quality, batch_id,
row_number() over (partition by batch_id order by id) as rn
from items
) i on i.batch_id = b.id
where rn <= b.size
group by b.id
order by b.id
From what I understand the count of defective items cannot be greater than the batch size.
EDIT: After reading your comments, I think using the RANK() function, and then join by rank and size should work for you. The following query attempts that.
SELECT b.id,
SUM(CASE WHEN i1.quality <= 3 THEN 1 ELSE 0END) as broken_item_count
FROM BATCH as b
LEFT JOIN (SELECT i.id, i.batch_id, i.quality,
RANK() OVER(PARTITION BY i.batch_id ORDER BY i.id) as RANK
FROM ITEMS as i) as i1 ON b.id = i1.batch_id AND i1.RANK <= b.size
GROUP BY b.id
EDIT2: Updated the query with a LEFT JOIN to cover the case where there are no samples in some batch.

Get the max value of a column from set of rows

I have a table like this
Table A:
Id Count
1 4
1 16
1 8
2 10
2 15
3 18
etc
Table B:
1 sample1.file
2 sample2.file
3 sample3.file
TABLE C:
Count fileNumber
16 1234
4 2345
15 3456
18 4567
and so on...
What I want is this
1 sample1.file 1234
2 sample2.file 3456
3 sample3.file 4567
To get the max value from table A I used
Select MAX (Count) from A where Id='1'
This works well but my problem is when combining data with another table.
When I join Table B and Table A, I need to get the MAX for all Ids and in my query I dont know what Id is.
This is my query
SELECT B.*,C.*
JOIN A on A.Id = B.ID
JOIN C on A.id = B.ID
WHERE (SELECT MAX(COUNT)
FROM A
WHERE Id = <what goes here????>)
To summarise, what I want is Values from Table B, FileNumber from Table c (where the count is Max for ID from table A).
UPDATE: COrrecting table C above. Looks like I need Table A.
I think this is the query you're looking for:
select b.*, c.filenumber from b
join (
select id, max(count) as count from a
group by id
) as NewA on b.id = NewA.id
join c on NewA.count = c.count
However, you should take into account that I don't get why for id=1 in tableA you choose the 16 to match against table C (which is the max) and for id=2 in tableA you choose the 10 to match against table C (which is the min). I assumed you meant the max in both cases.
Edit:
I see you've updated tableA data. The query results in this, given the previous data:
+----+---------------+------------+
| ID | FILENAME | FILENUMBER |
+----+---------------+------------+
| 1 | sample1.file | 1234 |
| 2 | sample2.file | 3456 |
| 3 | sample3.file | 4567 |
+----+---------------+------------+
Here is a working example
Using Mosty’s working example (renaming the keyword count to cnt for a column name), this is another approach:
with abc as (
select
a.id,
a.cnt,
rank() over (
partition by a.id
order by cnt desc
) as rk,
b.filename
from a join b on a.id = b.id
)
select
abc.id, abc.filename, c.filenumber
from abc join c
on c.cnt = abc.cnt
where rk = 1;
select
PreMax.ID,
B.FileName,
C2.FileNumber
from
( select C.id, max( C.count ) maxPerID
from TableC C
group by C.ID
order by C.ID ) PreMax
JOIN TableC C2
on PreMax.ID = C2.ID
AND PreMax.maxPerID = C2.Count
JOIN TableB B
on PreMax.ID = B.ID