How to display on a certain amount of data for a specific column - sql

Consider the following table
Dept product name parts WO
32 aa abc 11 1234
32 aa aas 18 2213
32 bb asd 16 3424
32 aa adf 19 1255
32 cc asa 10 7567
32 aa agd 11 1233
31 ss fsf 23 3434
I have around 100 dept. in my table. What I want is that when the dept. is 32 and the product is "aa", I only want to display 30 parts or less. So in this case the total number of parts for aa is 59. So the first aa product has 11 parts and the next aa product has 18 parts so that's 29. It should now ignore all the other aa products.
Expected Output
Dept product name parts WO
32 aa abc 11 1234
32 aa aas 18 2213
32 bb asd 16 3424
32 cc asa 10 7567
31 ss fsf 23 3434
Appreciate any help provided.

Assuming WO is a primary key then use SUM window function to solve it.
SELECT yt.Dept, yt.product, yt.name, yt.parts, yt.WO
FROM yourtable yt
LEFT JOIN (
SELECT *, sum(y.parts) over (partition by y.dept order by y.parts) tsum
FROM yourtable y
WHERE y.product = 'aa'
) t ON yt.WO= t.WO
WHERE yt.dept != 32 or (yt.dept = 32 and t.tsum < 59) or (yt.dept = 32 and yt.product != 'aa')

you can use SUM() window function where you have to partition by dept and product
SELECT dept,
product,
name,
parts,
wo
FROM (SELECT *,
SUM(parts) OVER (PARTITION BY dept, product ORDER BY name) rt
FROM t
) t_rt
WHERE rt <= 30
ORDER BY dept DESC,
product,
wo
Result
dept product name parts wo
32 aa abc 11 1234
32 aa aas 18 2213
32 bb asd 16 3424
32 cc asa 10 7567
31 ss fsf 23 3434

Related

Can someone help me to write the Oracle SQL query for the following data [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 12 months ago.
Improve this question
table1:
NAME
SAL
ab
34
ab
322
ab_d
34
ab_d
322
aa
34
aa
322
bb
34
bb
322
ac
65
ac_d
876
table 2:
col1
col2
col3
col4
ab
ab_d
aa
bb
ac
ac_d
ss
pp
this table2 also contains multiple rows
case 1: If I use table1.name = ab as a where condition,
the output should be,
ab, ab_d, aa, bb records
select * from table1 t1
where t1.name = 'ab';
NAME
SAL
ab
34
ab
322
ab_d
34
ab_d
322
aa
34
aa
322
bb
34
bb
322
(or)
case 2: If I use table2.col2 = ac_d as a where condition,
the output should be,
ac, ac_d, ss, pp records
select * from table1 t1
where t1.name = 'ac_d';
NAME
SAL
ac
34
ac
322
ac_d
34
ac_d
322
ss
34
ss
322
pp
34
pp
322
I am unable to write query....
You can do:
select y.*
from table2 x
join table1 y on y.name in (x.col1, x.col2, x.col3, x.col4)
where 'ab' in (x.col1, x.col2, x.col3, x.col4);
Result:
NAME SAL
----- ---
ab 34
ab 322
ab_d 34
ab_d 322
aa 34
aa 322
bb 34
bb 322
See running example at db<>fiddle.
The 3rd table is identical to the first table. Please provide CREATE TABLE scripts with data types, Primary keys and Foreign key constraints.
Looking at the structure of the 2nd table and the values in col2 in the first table I think you are going to need an UNPIVOT command
This will take the 2nd table and use the first column as an entity reference, take the column names from the other columns as use them as attributes and take the column value and use it as the value.
E.g. If you had a table:
Colour Jan Feb Mar
RED 20 15 12
BLUE 8 7 15
The UNPIVOT command would produce
Colour Month Amt
RED Jan 20
RED Feb 15
RED Mar 12
BLUE Jan 8
BLUE Feb 7
BLUE Mar 15

SQL query for Bill of Materials to get levels of components

I have got data that contains
parent_id
child_id
parent_desc
child_desc
123
24
AA
BB
123
81
AA
ZZ
24
32
BB
EE
32
45
EE
DD
45
57
DD
FF
57
62
FF
GG
62
7
GG
FA
81
9
ZZ
GA
What I want to achieve is to have a BOM explosion of it.
What I have come up is the below code:
create table test
( SurrogateKey bigint, ForeignKey bigint,mat_desc varchar,comp_desc varchar );
insert into test
values
( 123, 24,'AA','BB'),
(123,81,'AA','ZZ'),
( 24, 32,'BB','EE'),
( 32, 45,'EE','DD'),
( 45, 57,'DD', 'FF'),
( 57, 62,'FF','GG'),
( 62, 7,'GG','FA'),
(81,9,'ZZ','GA');
With traversal as
( SELECT test.SurrogateKey OriginKey,
ForeignKey,mat_desc,comp_desc
FROM test
WHERE SurrogateKey = 123 -- this first portion of the query generates the beginning set of records.
UNION ALL
SELECT traversal.OriginKey,
test.ForeignKey,traversal.mat_desc,test.comp_desc
FROM test
INNER JOIN traversal
ON test.SurrogateKey = traversal.ForeignKey -- we join back to the result set generated in the previous iteration of the recursion until no more nodes to travel to
)
select * from traversal
That is giving me a result:
parent_id
child_id
parent_desc
child_desc
123
24
AA
BB
123
81
AA
ZZ
123
32
AA
EE
123
9
AA
GA
123
45
AA
DD
123
57
AA
FF
123
62
AA
GG
123
7
AA
FA
But what I would like to achieve is to add column to see on which level the child is so thirst three rows would look like this, and so on
parent_id
child_id
parent_desc
child_desc
level
123
24
AA
BB
1
123
81
AA
ZZ
1
123
32
AA
EE
2
123
9
AA
GA
123
45
AA
DD
123
57
AA
FF
123
62
AA
GG
123
7
AA
FA
Maybe someone has got idea, how to solve this. Maybe some window function, or how to come up with some counter to have it using recursive cte
Thank you all in advance
If I understand correctly, you want to enumerate the rows based on the tree-depth. You correctly recognize that you can do this with a recursive CTE.
The syntax for recursive CTEs varies depending on the databases, but the idea is:
with recursive cte as (
select t.SurrogateKey, t.ForeignKey, t.mat_desc, t.comp_desc, t.mat_desc as orig_mat_desc, 1 as lev
from test t
where not exists (select 1 from test t2 where t2.comp_desc = t.mat_desc)
union all
select t.SurrogateKey, t.ForeignKey, t.mat_desc, t.comp_desc, cte.orig_mat_desc, 1 + lev
from cte join
test t
on cte.comp_desc = t.mat_desc
)
select *
from cte;
Here is a db<>fiddle.

SQL LOGIC using 3conditions

course_completions CC
id coursemodid userid state timemodified
370 23 2 1 1433582890
329 24 89 1 1427771915
333 30 39 1 1428309816
332 32 39 1 1428303307
327 33 40 1 1427689703
328 34 89 1 1427710711
303 35 41 1 1410258482
358 36 99 1 1432020067
365 25 2 1 1433142455
304 26 69 1 1410717866
353 37 95 1 1430387005
416 38 2 1 1438972465
300 27 70 1 1409824001
302 29 74 1 1412055704
297 30 2 1 1409582123
301 133 41 1 1410255923
336 133 91 1 1428398435
364 133 40 1 1433142348
312 133 85 1 1425863621
course_modules CM
id course
23 6
24 6
25 6
26 6
27 6
28 6
29 8
30 8
31 8
32 8
33 8
34 5
35 5
36 5
37 5
38 5
39 9
40 9
41 9
course_mod_settings CMS
id course modinstance
27 8 30
28 8 31
29 8 32
30 8 33
31 6 23
32 6 24
33 6 25
34 6 26
35 6 27
36 6 28
37 9 39
38 9 40
39 9 41
I need the count of each user has Completed modules, Inprocess modules and Notstarted modules for each course, where getting the count of userids from table CC by taking courseia from table CM, get number of modules that an user has completed from each course.
(A course can have morethan one module and a course can have number of users attempted all modules, few modules or not attempted at all).
So, I need number of users - has done number of modules - in a course. (3 logics)
Completed.Users means : If number of modules attempted is equal to number of modinstance from table CMS (ex: no. of modules attempted by a user per course= 9, no.modinstance = 9. Because 7 is not equal to 9, They are completed.)
Inprocess.Users means : Number of modules attempted should be >0, but not equal to [count(modinstance) per course] (ex: no. of modules attempted by a user per course= 7 , no.modinstance = 9. Because 7 is not equal to 9, They are Inprocess.)
Notstarted.Users means : Number of modules attempted should be equal to 0, (ex: no. of modules attempted by a user per course= 0. They are Notstarted).
OUTPUT :
Course No.Completed.Users No.Inprocess.Users No.Notstarted.Users
5 65 32 6
6 40 12 15
8 43 56 0
9 0 7 9
Sir, this is a very critical logic that I was trying, I couldn't get a solution. I hope stackoverflow developers could help me out. I tried with my query :
SELECT cm.course AS "Course",
(CASE WHEN
(SELECT count(cms.id) FROM course_mod_settings cms) =
(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 )
THEN COUNT(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 ) END) AS "No.Completed.Users",
(CASE WHEN
(SELECT count(cms.id) FROM course_mod_settings cms) > 0 AND
(SELECT count(cms.id) FROM course_mod_settings cms) !=
(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 )
THEN COUNT(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 ) END) AS "No.Inprocess.Users",
(CASE WHEN
(SELECT count(cms.id) FROM course_mod_settings cms) = 0
THEN COUNT(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 ) END) AS "No.Notstarted.Users"
FROM
mdl_course c
GROUP BY c.id
SQL Fiddle
SELECT course AS "Course",
SUM(CASE WHEN completion_count = module_count THEN 1 ELSE 0 END) AS "No.Completed.Users",
SUM(CASE WHEN completion_count > 0 AND completion_count < module_count THEN 1 ELSE 0 END) AS "No.Inprocess.Users",
SUM(CASE WHEN completion_count = 0 THEN 1 ELSE 0 END) AS "No.Notstarted.Users"
FROM (SELECT course, COUNT(*) AS module_count
FROM course_modules cm
GROUP BY course) course_module_counts JOIN
(SELECT cm.course AS courseid, users.id AS userid, SUM(CASE WHEN cc.state = 1 THEN 1 ELSE 0 END) completion_count
FROM ((SELECT DISTINCT userid AS id FROM course_completions) users CROSS JOIN course_modules cm) LEFT JOIN course_completions cc ON users.id = cc.userid AND cc.coursemodid = cm.id
GROUP BY cm.course, users.id) course_completion_counts
ON course_module_counts.course = course_completion_counts.courseid
GROUP BY course
gives this output, which matches the limited dataset that you provided in your question.
| course | No.Completed.Users | No.Inprocess.Users | No.Notstarted.Users |
|--------|--------------------|--------------------|---------------------|
| 5 | 0 | 5 | 7 |
| 6 | 0 | 4 | 8 |
| 8 | 0 | 4 | 8 |
| 9 | 0 | 0 | 12 |

SQLite equivalent query of the given MSSQL query.

I've been trying to find a way to use the row_number over partition by, but couldn't find how to do so in SQLite.
I'm trying to convert the following the working query from MSSQL syntax to SQLite:
select TKG, hour, CAP, switch, Calls
from
(
select *,
row_number() over(partition by TKG order by cap desc) rn
from yourtable
) t1
where rn = 1
Here's an example with SQLFiddle: http://sqlfiddle.com/#!3/7bf9a/3
Basically, I have the following table:
TKG hour CAP SWITCH CALLS
AAA 7 45 HH 56
AAA 8 35 HH 76
AAA 9 25 HH 43
BBB 7 32 LL 5
BBB 8 43 LL 65
BBB 9 434 LL 65
CCC 7 54 JJ 43
CCC 8 564 JJ 43
CCC 9 54 JJ 65
ddd 7 10 MM 4
ddd 8 10 MM 3
ddd 9 10 MM 5
I need to order by the TKG with the max CAP so the output will look like this:
TKG hour CAP SWITCH CALLS
AAA 7 45 HH 56
BBB 9 434 LL 65
CCC 8 564 JJ 43
ddd 7 10 MM 4
Without knowing unique key it's really hard to do in readable way (no cross apply, no windowed functions). If you can afford to add id into your table, you can do:
select *
from yourtable
where
id in (
select min(y.id)
from yourtable as y
inner join (
select [TKG], max([CAP]) as [CAP]
from yourtable
group by [TKG]
) as y2 on y2.[TKG] = y.[TKG] and y2.[CAP] = y.[CAP]
group by y.[TKG]
)
sql fiddle demo
Considering myself lucky that I don't work in SQLite often :)

sum of two field in two table

I have four tables in the database as follows:
tblInvoice:
invcid,customerid,invoicedate
tblInvcDetail:
ID,invcid,item,itemprice,itemquantity
tblPay:
payid,invcid,paydate
tblPayDetail:
payid,amount
I need to create a list of invoiceid, invoicedate, (sum of itemprice*itemquantity), (sum of amount) where userid is given.
I tried this query:
SELECT tblinvoice.invcid,
tblinvoice.invcdate,
Sum(tblinvcdetail.itemprice * tblinvcdetail.itemquantity) AS SumOfInvoice,
Sum(tblpaydetail.amount) AS SumOfAmount
FROM ((tblinvoice
LEFT JOIN tblpay
ON tblinvoice.invcid = tblpay.invcid)
LEFT JOIN tblinvcdetail
ON tblinvoice.invcid = tblinvcdetail.invcid)
LEFT JOIN tblpaydetail
ON tblpay.payid = tblpaydetail.payid
GROUP BY tblinvoice.invcid,
tblinvoice.invcdate;
But the result is not quite correct
Please help me.
Thanks a lot.
Sample data:
tblInvoice:
invcid customerid invcdate |invcsum(manualy calculated)
18 8 6/30/2012 |$140,000
39 8 7/12/2012 |$170,000
40 8 7/12/2012 |$80,000
43 8 7/14/2012 |$80,000
44 8 7/14/2012 |$80,000
45 8 7/15/2012 |$700,000
46 8 7/17/2012 |$180,000
tblInvcDetail:
ID invccid itemname itemprice itemquantity
19 18 X $70,000 2
92 39 Y $80,000 1
93 39 Z $90,000 1
94 40 Y $80,000 1
97 43 Y $80,000 1
98 44 Y $80,000 1
99 45 W $700,000 1
100 46 Y $80,000 1
101 46 U $100,000 1
tblPay:
payid invcid paydate |AmountSUM(Manually Calculated)
35 18 7/11/2012 |$120,000
40 18 7/12/2012 |$147,000
41 40 7/12/2012 |$84,000
44 44 7/14/2012 |$84,000
46 45 7/15/2012 |$700,000
tblPayDetail:
payid amount
35 $100,000
35 $20,000
40 $147,000
41 $84,000
44 $84,000
46 $700,000
And finally the query result is:
invcid invcdate SumOfInvoice SumOfAmount
18 6/30/2012 $420,000.00 $267,000.00
39 7/12/2012 $170,000.00
40 7/12/2012 $80,000.00 $84,000.00
43 7/14/2012 $80,000.00
44 7/14/2012 $80,000.00 $84,000.00
45 7/15/2012 $700,000.00 $700,000.00
46 7/17/2012 $180,000.00
You can see that the calculation is wrong in the first row (SumOfInvoice column)
and the rest is correct!
How about:
SELECT a.invcid,
a.invcdate,
a.sumofinvoice,
b.sumofamount
FROM (SELECT ti.invcid,
ti.invcdate,
SUM(td.itemprice * td.itemquantity) AS SumOfInvoice
FROM tblinvoice AS ti
LEFT JOIN tblinvcdetail AS td
ON ti.invcid = td.invcid
GROUP BY ti.invcid,
ti.invcdate) a
LEFT JOIN (SELECT tp.invcid,
SUM(tpd.amount) AS SumOfAmount
FROM tblpay AS tp
LEFT JOIN tblpaydetail AS tpd
ON tp.payid = tpd.payid
GROUP BY tp.invcid) b
ON a.invcid = b.invcid