Grouped / pivot query in SQL - sql

I am looking to find a query to link data from one table to an other table. both tables contain the same order ID and part ID. but one table has 4 lines for every piece. the PRFNAME field should be added in a separated column.
Table 1 : IDBGPL
ID;ORDERID;CNT;NAME1;MATNAME;MATGRID;SURFTLEN;SURFTWIDTH
16385;Project_Name_1;1;Corpuszijde;EG_ED_Px_W1001_ST9_18;0;2146;138
16386;Project_Name_1;1;Corpuszijde;EG_ED_Px_W1001_ST9_18;0;2146;50
16385;Project_Name_2;1;Zijde Rechts;EG_ED_Px_W1001_ST9_18;0;888;519,2
Table 2: IDBPRF
ID;ORDERID;PRFNO;PRFID
16385;Project_Name_1;1;PRF_Verstek_Overmaat_25
16385;Project_Name_1;2;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_1;3;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_1;4;PRF_EG_ABS_W1000_ST9_2
16386;Project_Name_1;1;PRF_Verstek_Overmaat_25
16386;Project_Name_1;2;PRF_EG_ABS_W1000_ST9_2
16386;Project_Name_1;3;PRF_00_Overmaat_25
16386;Project_Name_1;4;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_2;1;EG_ABS_H3335_ST28_08_75
16385;Project_Name_2;2;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_2;3;PRF_00
16385;Project_Name_2;4;PRF_EG_ABS_W1000_ST9_2
This is the desired result from the query:
ID;ORDERID;NAME1;Kant 1 (PRFNO = 1);Kant 2 (PRFNO = 2);Kant 3 (PRFNO = 3);Kant 4 (PRFNO = 4)
16385;Project_Name_1;Corpuszijde;PRF_Verstek_Overmaat_25;PRF_EG_ABS_W1000_ST9_2;PRF_EG_ABS_W1000_ST9_2;PRF_EG_ABS_W1000_ST9_2
16386;Project_Name_1;Corpuszijde;PRF_Verstek_Overmaat_25;PRF_EG_ABS_W1000_ST9_2;PRF_00_Overmaat_25;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_2;Zijde Rechts;EG_ABS_H3335_ST28_08_75;PRF_EG_ABS_W1000_ST9_2;PRF_00;PRF_EG_ABS_W1000_ST9_2
Here is a link to some example data in Excel:
https://rasgroup-my.sharepoint.com/:x:/g/personal/maarten_de_potter_ras-group_eu/Ec-PvcsV5GhFuademkU83JcBiob28FicrUr3Kl9-VkPE7Q?e=sqOYUu
The closest i got to a result was this query, but then I was not able to group the 4 part lnes to one.
enter image description here
SELECT
a.ID AS A_ID ,
a.ORDERID AS A_ORDERID,
b.ID AS B_ID ,
b.ORDERID AS B_ORDERID,
b.NAME1,
(CASE WHEN a.PRFNO = 1 THEN a.PRFID END) AS Kant1,
(CASE WHEN a.PRFNO = 2 THEN a.PRFID END) AS Kant2,
(CASE WHEN a.PRFNO = 3 THEN a.PRFID END) AS Kant3,
(CASE WHEN a.PRFNO = 4 THEN a.PRFID END) AS Kant4
FROM
IDBPRF a, IDBGPL b
WHERE
a.ORDERID = b.ORDERID
AND a.ID = b.ID
Hopefully someone could help me with solving this puzzle.

Related

SQL Server Select Statement Columns

Original Query:
select StudyID, count(CompletedDate), count(Removed), count(RemovalReason)
from Study a
full outer join Households b
on a.HouseholdID = b.HouseholdID
where StudyID = '123456'
and Removed = 1
and RemovalReason = 5
group by StudyID
How do I write out this query so that for each column (CompletedDate, Removed, and RemovalReason) is not restricted to the conditions (i.e. Removed = 1, Removal Reason = 5) and only applies to the specific column. If I execute this query, it will not show me the total count for CompletedDate because I'm restricting it to these conditions. Is there a way to write it directly next to count?
Table/Columns - Study:
HouseholdID (primary key),
StudyID,
CompletedDate
Table/Columns - Households:
HouseholdID (primary key),
Removed,
RemovalReason
I think you are looking for something like this, but your question is a little loose with details:
select StudyID
, count(CompletedDate)
, sum(case when Removed = 1 then 1 else 0 end)
, sum(case when RemovalReason = 5 then 1 else 0 end)
from Study a
join Households b
on a.HouseholdID = b.HouseholdID
where StudyID = '123456'
group by StudyID

How to get fields from multiple tables

I want to get fields from 2 different tables . The last field candidate_score_id has a many to one relationship. So how should I join the below 2 queries
1) To get candidate_score_id from the candidate_score table.
select candidate_score_id from candidate_score a where
a.assessment_id = NEW.assessment_id and
a.candidate_id = NEW.candidate_id and
a.attempt_Count = NEW.attempt_count;
2) To insert different fields in to the candidate_score_details table. The field in this table should be obtained by query above.
insert into candidate_score_details(candidate_score_details_id, candidate_id, assessment_id, attempt_count, score_type, score_tag,correct, candidate_score_id)
select uuid();
select a.candidate_id, a.assessment_id,a.attempt_count,"BY-COMPLEXITY",
case c.complexity
when 1 then "HIGH"
when 2 then "MEDIUM"
when 3 then "LOW"
end, count(*) from candidate_answer a, answer_key b, question_meta_data c where a.candidate_id = NEW.candidate_id and
a.assessment_id = NEW.assessment_id and
a.attempt_count = NEW.attempt_count and
a.assessment_id = b.assessment_id and
a.question_id = b.question_number and
a.response = b.answer and
a.question_id = c.question_number
group by a.candidate_id, a.assessment_id, a.attempt_count, c.complexity;
Just looking at the SQL joining aspect of your question, you'll need to specify the table I THINK you're aliasing a 2nd table with the "NEW" reference. If that's the case, then the query would be (replacing "OTHER_TABLE_NAME" with the name of the 2nd table:
select a.candidate_score_id
from candidate_score a
left join OTHER_TABLE_NAME new on
and a.assessment_id = NEW.assessment_id
and a.candidate_id = NEW.candidate_id
and a.attempt_Count = NEW.attempt_count
Seems that Query 1 has the same 3 criteria on the "candidate_score" table as for the "candidate_answer" table in Query 2.
So how about adding a LEFT JOIN of "candidate_score" to "candidate_answer" on those 3 fields?
For example:
INSERT INTO candidate_score_details
(
candidate_score_details_id,
candidate_id,
assessment_id,
attempt_count,
score_type,
score_tag,
correct,
candidate_score_id
)
SELECT
uuid(),
answer.candidate_id,
answer.assessment_id,
answer.attempt_count,
'BY-COMPLEXITY' AS score_type,
(CASE meta.complexity
WHEN 1 THEN 'HIGH'
WHEN 2 THEN 'MEDIUM'
WHEN 3 THEN 'LOW'
END) AS score_tag,
COUNT(*) AS correct,
MAX(score.candidate_score_id) AS max_candidate_score_id
FROM candidate_answer AS answer
JOIN answer_key AS akey
ON (akey.assessment_id = answer.assessment_id AND akey.question_number = answer.question_id AND akey.answer = answer.response)
LEFT JOIN candidate_score AS score
ON (score.candidate_id = answer.candidate_id AND score.assessment_id = answer.assessment_id AND score.attempt_count = answer.attempt_count)
LEFT JOIN question_meta_data AS meta
ON meta.question_number = answer.question_id
WHERE answer.candidate_id = NEW.candidate_id
AND answer.assessment_id = NEW.assessment_id
AND answer.attempt_count = NEW.attempt_count
GROUP BY answer.candidate_id, answer.assessment_id, answer.attempt_count, meta.complexity;

SQL - How to find entries where a value is missing between two rows

We are using Presto SQL at my job. I have spent hours trying to search for the answer to this question but can't find an answer and it's quite difficult to search for. Solving this issue opens the door to fixing a lot of problems.
I need to write a query that tries to find all entries where REQUEST_CANCEL & CHARGED exist but CANCEL_ACCOUNT is missing.
CHARGED & CANCEL_ACCOUNT should always come after REQUEST_CANCEL.
Table Name: CUSTOMER_INFO
|DATE_TIME|CUST_ID |ACTION |
|20180726 |1234 |CHARGED |
|20180726 |1234 |CANCEL_ACCOUNT|
|20180726 |1234 |REQUEST_CANCEL|
All these values exist in the same table. Here's what I have so far.
SELECT *
FROM
(SELECT *
FROM CUSTOMER_INFO
WHERE
DATE_TIME = 20180726
AND ACTION = REQUEST_CANCEL) as a
JOIN
(SELECT *
FROM CUSTOMER_INFO
WHERE
DATE_TIME = 20180726
AND ACTION = CHARGED) as b
ON a.CUST_ID = b.CUST_ID
WHERE
a.TIME < b.TIME
Let me explain it in a way that makes sense.
A = REQUEST_CANCEL
B = CANCEL_ACCOUNT
C = CHARGED
How do you query for when A and C exist but B is missing. The sequence needs to be exact A > B > C. It's essentially querying for something that doesn't exist between two values that do exist. In my current query, B can be returned between the two values and that's NOT what I want.
I think you're searching for NOT EXISTS and a corellated subquery.
SELECT *
FROM (SELECT *
FROM customer_info
WHERE action = 'REQUEST_CANCEL') rc
INNER JOIN (SELECT *
FROM customer_info
WHERE action = 'CHARGED') c
ON c.cust_id = rc.cust_id
AND c.date_time >= rc.date_time
WHERE NOT EXISTS (SELECT *
FROM customer_info ca
WHERE ca.cust_id = rc.cust_id
AND ca.action = 'CANCEL_ACCOUNT'
AND ca.date_time >= rc.date_time
AND ca.date_time <= c.date_time);
Use group by and having:
select cust_id
from customer_info ci
where date_time = 20180726 and
action in ('REQUEST_CANCEL', 'CHARGED', 'CANCEL_ACCOUNT')
group by cust_id
having sum(case when action = 'REQUEST_CANCEL' then 1 else 0 end) > 0 and
sum(case when action = 'CHARGED' then 1 else 0 end) > 0 and
sum(case when action = 'CANCEL_ACCOUNT' then 1 else 0 end) = 0 ;
Each sum() counts the number of matching records for the customer with that action. The > 0 says that one exists. The = 0 says that none exist.
The database doesn't matter for this logic. Here is a SQL Fiddle using MySQL.

SQL AVG statement another table

I'm having trouble with a SQL query. The goal is to see only the certain entries on a specific date (I got this already) which have an average score below 1 in their last 5 home games.
You can see the tables here:
http://dbup2date.uni-bayreuth.de/downloads/bundesliga/Klassendiagramm_Bundesliga.pdf
I have this code so far:
SELECT
A.Spieltag, A.Datum, A.Uhrzeit, B.Name AS Heim
FROM
Spiel AS A
JOIN
Verein AS B ON A.Heim = B.V_ID AND B.Liga = 1
WHERE
Spieltag = 5
HAVING
AVG(SELECT Tore_Heim
FROM Spiel AS A
JOIN Verein AS B
WHEN A.Heim = B.V_ID) < 1
Sorry for my bad English
Thank you
Make sure you group by any =fields that you are not aggregating on when you use HAVING. And you can simplify that HAVING clause since you are already referencing those exact tables in your FROM:
SELECT
A.Spieltag, A.Datum, A.Uhrzeit, B.Name AS Heim
FROM
Spiel AS A
JOIN
Verein AS B ON A.Heim = B.V_ID AND B.Liga = 1
WHERE
Spieltag = 5
GROUP BY A.Spieltag, A.Datum, A.Uhrzeit, B.Name
HAVING
AVG(Tore_Heim) < 1

SQL Condition for sum

I have a sql statement with many inner join tables, as you can see below I have many conditional SUM statements , these sums are giving me wrong (very large) numbers as the inner join is repeating the same values in my source select pool. I was wondering id there is a way to limit these sum conditions lets say to EMPLIDs. The code is :
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
SUM(C.FACTOR_XSALARY) AS X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
COUNT(D.EMPLID),
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
(SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END)+SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END))*100/(COUNT(A.EMPLID)) AS PEpercent
FROM
EMP_DTL A INNER JOIN EMPL_CTG_L1 B ON A.EMPL_CTG = B.EMPL_CTG
INNER JOIN
ECM_PRYR_VW C ON A.EMPLID=C.EMPLID
INNER JOIN ECM_INELIG D on D.EMPL_CTG=A.EMPL_CTG and D.YEAR=YEAR(getdate())
WHERE
A.YEAR=YEAR(getdate())
AND B.EFF_STATUS='A'
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY B.DESCR
I already tried moving D.YEAR=YEAR(getdate()) to the where clause. Any help would be greatly appereciated
The probable reason of your very large numbers is probably due to the result of Cartesian product of joining A -> B, A -> C and A -> D where tables C and D appear to have multiple records. So, just example... if A has 10 records, and C has 10 for each of the A records, you now have 10 * 10 records... Finally, join that to D table with 10 records, you now have 10 * 10 * 10 for each "A", thus your bloated answers.
Now, how to resolve. I have taken your "C" and "D" tables and "Pre-Aggregated" those counts based on the join column basis. This way, they will each have only 1 record with the total already computed at that level, joined back to A table and you lose your Cartesian issue.
Now, for table B, it appears that is a lookup table only and would only be a single record result anyhow.
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
PreAggC.X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
PreAggD.DCount,
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
( SUM( CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END
+ CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END ) *
100 / COUNT(A.EMPLID) AS PEpercent
FROM
EMP_DTL A
INNER JOIN EMPL_CTG_L1 B
ON A.EMPL_CTG = B.EMPL_CTG
AND B.EFF_STATUS='A'
INNER JOIN ( select
C.EMPLID,
SUM(C.FACTOR_XSALARY) AS X_Programp
from
ECM_PRYR_VW C
group by
C.EMPLID ) PreAggC
ON A.EMPLID = PreAggC.EMPLID
INNER JOIN ( select
D.EMPLID,
COUNT(*) AS DCount
from
ECM_INELIG D
where
D.Year = YEAR( getdate())
group by
D.EMPLID ) PreAggD
ON A.EMPLID = PreAggD.EMPLID
WHERE
A.YEAR=YEAR(getdate())
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY
B.DESCR