Exclude Row with Same ID but Different Secondary Column Value - sql

Im trying to exclude a record if the ID (PK) is the same but a secondary column value is different.
So in my example below, I have two different codes E03_Port and E12_PortfNotDef for a single ID, so basically, I want to exclude the E12_PortfNotDef record if E01.. through E04.. codes are triggered.
SELECT *
FROM (
SELECT ID, Code,
MAX(CASE WHEN Code = 'E01_Matured' THEN 1 Else NULL END) AS Matured,
MAX(CASE WHEN Code = 'E02_Terminated' THEN 2 Else NULL END) AS Terminated,
MAX(CASE WHEN Code = 'E03_Port' THEN '3' Else NULL END) AS Port,
MAX(CASE WHEN Code = 'E04_Swap' THEN 4 Else NULL END) AS Swap,
MAX(CASE WHEN Code = 'E12_PortfNotDef' THEN '12' Else NULL END) AS Port_Not_Def
FROM EXCLUDED
GROUP BY ID, Code
)
WHERE COALESCE(Matured, Terminated, Port, Swap Port_Not_Def) IS NOT NULL
AND ID = '120320AC'
ORDER BY ID;
Actual Results:
ID Code Matured Terminated Port Swap Port_Not_Def
120320AC E03_Port 3
120320AC E12_PortfNotDef 12
Expected Results:
ID Code Matured Terminated Port Swap Port_Not_Def
120320AC E03_Port 3

There's a trivial way might be applied by using row_number() window analytic function :
SELECT *
FROM (
SELECT ID, Code,
MAX(CASE WHEN Code = 'E01_Matured' THEN 1 Else NULL END) AS Matured,
MAX(CASE WHEN Code = 'E02_Terminated' THEN 2 Else NULL END) AS Terminated,
MAX(CASE WHEN Code = 'E03_Port' THEN '3' Else NULL END) AS Port,
MAX(CASE WHEN Code = 'E04_Swap' THEN 4 Else NULL END) AS Swap,
MAX(CASE WHEN Code = 'E12_PortfNotDef' THEN '12' Else NULL END) AS Port_Not_Def,
ROW_NUMBER() OVER (PARTITION BY Code ORDER BY ID, Code) AS RN
FROM EXCLUDED
GROUP BY ID, Code)
WHERE COALESCE(Matured, Terminated, Port, Swap Port_Not_Def) IS NOT NULL
AND ID = '120320AC'
AND RN = 1
ORDER BY ID

I ended up restricting the ID's in the FROM Clause to not show those where Code was E01-E04.

Related

Remove duplicate rows when using CASE WHEN statement

I am currently generating a table which converts the rows value to the new column, the following is my code:
SELECT ref_no,
(CASE WHEN code = 1 THEN code END) AS 'count_1',
(CASE WHEN code = 2 THEN code END) AS 'count_2',
(CASE WHEN code = 3 THEN code END) AS 'count_3',
(CASE WHEN code = 4 THEN code END) AS 'count_4',
(CASE WHEN code = 5 THEN code END) AS 'count_5',
(CASE WHEN code = 6 THEN code END) AS 'count_6'
FROM data"
The output is:
However, I needs those duplicated rows to be combined, is there any way to do? I don't need to sum up those values as there is no overlap among them.
I've tried with group by but it does not work as expected:
My expected out put is like:
ref c_1 c_2 c_3 c_4 c_5 c_6
1 1 2 3 - - -
This shows adding ORDER BY clause does not work in my context.
Updated: complete query in sqldf
The answer is: YES
By using GROUP BY and MAX like this:
SELECT ref_no,
max(CASE WHEN code = 1 THEN code END) AS 'count_1',
max(CASE WHEN code = 2 THEN code END) AS 'count_2',
max(CASE WHEN code = 3 THEN code END) AS 'count_3',
max(CASE WHEN code = 4 THEN code END) AS 'count_4',
max(CASE WHEN code = 5 THEN code END) AS 'count_5',
max(CASE WHEN code = 6 THEN code END) AS 'count_6'
FROM data
GROUP BY ref_no
ORDER BY ref_no
You could use PIVOT for this
SELECT *
FROM (
SELECT ref_no, code FROM data
) data
PIVOT (
max(code) FOR code IN ([1], [2], [3], [4], [5], [6])
) pivoted
The easiest would either be to use GROUP BY or a PIVOT function.
GROUP BY example below:
SELECT ref_no,
sum(CASE WHEN code = 1 THEN code ELSE 0 END) AS 'count_1',
sum(CASE WHEN code = 2 THEN code ELSE 0 END) AS 'count_2',
sum(CASE WHEN code = 3 THEN code ELSE 0 END) AS 'count_3',
sum(CASE WHEN code = 4 THEN code ELSE 0 END) AS 'count_4',
sum(CASE WHEN code = 5 THEN code ELSE 0 END) AS 'count_5',
sum(CASE WHEN code = 6 THEN code ELSE 0 END) AS 'count_6'
FROM data
GROUP BY ref_no
A really long way of doing this using your existing code and a CTE table:
WITH results as (
SELECT ref_no,
(CASE WHEN code = 1 THEN code END) AS 'count_1',
(CASE WHEN code = 2 THEN code END) AS 'count_2',
(CASE WHEN code = 3 THEN code END) AS 'count_3',
(CASE WHEN code = 4 THEN code END) AS 'count_4',
(CASE WHEN code = 5 THEN code END) AS 'count_5',
(CASE WHEN code = 6 THEN code END) AS 'count_6'
FROM data)
SELECT
ref_no
, sum(coalesce(count_1),0) -- for sum
, max(coalesce(count_1),0) -- for just the highest value
-- Repeat for other ones
FROM
results
GROUP BY
ref_no

PostgreSQl: select multiple rows and make it in one row

I'm using PostgreSQl and this is my table in database:
how can I write a query that gives me this result :
or you can write query like
select id_salarie,
max(case when date_pointage = '2015-01-01' then round(nb_heures::numeric,2) else null end) as "2015-01-01",
max(case when date_pointage = '2015-01-02' then round(nb_heures::numeric,2) else null end)as "2015-01-02",
max(case when date_pointage = '2015-01-03' then round(nb_heures::numeric,2) else null end) as "2015-01-03"
from my_table where id_salarie = 1
group by id_salarie;
Query looks huge and terrible but works for cubes

Getting a sum of only the first instance of a column in a sql query

I have the following SQL code:
SELECT EmployeeID,
SUM(CASE
WHEN Error1 = '0'
THEN 1
ELSE 0
END + CASE
WHEN Error2 = '0'
THEN 1
ELSE 0
END + CASE
WHEN Error3 = '0'
THEN 1
ELSE 0
END) AS TotalErrors
FROM SubmittedDocuments
GROUP BY EmployeeID
The statement should calculate the number of errors in the table for each employee. However, there is another column in the table SubmittedDocuments named "DocumentName". How could I write a statement that only counts errors for the first instance of each DocumentName? (Or only counts for the one with the lowest "SubmittedID", the unique identifier)
Sorry if anything in unclear, I will attempt to clear up any confusion in the comments.
I might have not got this right from your question, but I think this should work. If you could show some sample data and expected output then we can definitely have a sure answer.
SELECT EmployeeID
SUM(CASE WHEN DocIDErr > 1 THEN 0 ELSE 1 END)
FROM
(SELECT EmployeeID
, Error1
, ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY DocumentName) AS DocIDErr
FROM SubmittedDocuments) AS RS
GROUP BY EmployeeID
I don't think you want aggregation. I think you just want to select the first document for each name.
If so, this may be what you want:
select sd.*,
((case when error1 = '0' then 1 else 0 end) +
(case when error2 = '0' then 1 else 0 end) +
(case when error3 = '0' then 1 else 0 end)
) as numerrors
from (select sd.*,
row_number() over (partition by documentname order by submittedid) as seqnum
from SumittedDocuments sd
) sd
where seqnum = 1;

methods to separate multiple count(*)s by external field

I didn't know exactly what to call this question, so apologies if the title is confusing. I'm trying to generate a summary of user activity for a particular website. This query returns the total number of hits per type of page:
select
count(case when internal_handle = 'content' then 1 else null end) as CONTENT,
count(case when data = '/webapps/assessment/take/launch.jsp' then 1 else null end) as ASSESSMENTS,
count(case when internal_handle = 'discussion_board_entry' then 1 else null end) as DISCUSSIONS,
count(case when data = '/webapps/blackboard/execute/uploadAssignment' then 1 else null end) as BB_ASSIGNMENTS,
count(case when data = '/webapps/turn-plgnhndl-BBLEARN/links/submit.jsp' then 1 else null end) as TII_ASSIGNMENTS,
count(case when data = '/webapps/osv-kaltura-BBLEARN/jsp/courseGallery.jsp' then 1 else null end) as COURSE_GALLERY,
count(case when data = '/webapps/osc-BasicLTI-BBLEARN/frame.jsp' then 1 else null end) as ECHO_360,
count(case when internal_handle = 'check_grade' then 1 else null end) as MY_GRADES
from BBLEARN.ACTIVITY_ACCUMULATOR
where course_pk1 = (select pk1 from BBLEARN.course_main where course_id = '2014FA.BOS.PPB.445.A')
and user_pk1 in (select users_pk1 from BBLEARN.course_users where role = 'S' and crsmain_pk1 = course_pk1);
So the result is like:
CONTENT,ASSESSMENTS,DISCUSSIONS,BB_ASSIGNMENTS,TII_ASSIGNMENTS,COURSE_GALLERY,ECHO_360,MY_GRADES
5787,954,335,0,0,0,837,222
My goal, though, is to have it separated by hits per user. For instance, I'd want a result like:
USER_PK1,CONTENT,ASSESSMENTS,DISCUSSIONS,BB_ASSIGNMENTS,TII_ASSIGNMENTS,COURSE_GALLERY,ECHO_360,MY_GRADES
USER_A,250,79,41,0,0,0,66,7
USER_B,144,89,82,0,0,0,24,0
USER_C,174,45,23,0,0,0,58,1
--etcetera
I can imagine running the above query iteratively, but I'm not familiar enough with Oracle to do it effectively. How might I go about doing this? Or is there a better way to get the fields I'm looking for?
Thanks in advance!
Just add a group by:
select user_pk1,
count(case when internal_handle = 'content' then 1 else null end) as CONTENT,
count(case when data = '/webapps/assessment/take/launch.jsp' then 1 else null end) as ASSESSMENTS,
count(case when internal_handle = 'discussion_board_entry' then 1 else null end) as DISCUSSIONS,
count(case when data = '/webapps/blackboard/execute/uploadAssignment' then 1 else null end) as BB_ASSIGNMENTS,
count(case when data = '/webapps/turn-plgnhndl-BBLEARN/links/submit.jsp' then 1 else null end) as TII_ASSIGNMENTS,
count(case when data = '/webapps/osv-kaltura-BBLEARN/jsp/courseGallery.jsp' then 1 else null end) as COURSE_GALLERY,
count(case when data = '/webapps/osc-BasicLTI-BBLEARN/frame.jsp' then 1 else null end) as ECHO_360,
count(case when internal_handle = 'check_grade' then 1 else null end) as MY_GRADES
from BBLEARN.ACTIVITY_ACCUMULATOR
where course_pk1 = (select pk1 from BBLEARN.course_main where course_id = '2014FA.BOS.PPB.445.A') and
user_pk1 in (select users_pk1 from BBLEARN.course_users where role = 'S' and crsmain_pk1 = course_pk1)
group by user_pk1;
If user_pk1 isn't what you mean by "user", then you might have to join in another table.

Summarize multiple transactions that share a common value but also have unique row identifiers

I'm currently working with a data set that has a large number of unique groups, and within each group there could be one to many unique rows, to describe the type of transaction applicable to that group. There are a limited number of types of transactions, and each transaction has a(n):
Amount
Location
Date
The data set would look something like this:
What I would like it to do is combine all groups into a single line, and have three columns for each type of transaction. I am trying to get the end result to look like this:
The closest I have gotten is to try a number of joins, based on the claim number while looking for the unique key. Unfortunately my results end up looking like this:
Any suggestions on how to get each unique Group to have only one row in the results, with the three Types spread out, having three columns each?
You can do this all with conditional aggregation:
select grp,
sum(case when type = 'S' then amount else null end) as type_s_amt,
min(case when type = 'S' then location else null end) as type_s_loc,
min(case when type = 'S' then date else null end) as type_s_dt,
sum(case when type = 'O' then amount else null end) as type_o_amt,
min(case when type = 'O' then location else null end) as type_o_loc,
min(case when type = 'O' then date else null end) as type_o_dt,
sum(case when type = 'F' then amount else null end) as type_f_amt,
min(case when type = 'F' then location else null end) as type_f_loc,
min(case when type = 'F' then date else null end) as type_f_dt
from tbl
group by grp
Fiddle: http://sqlfiddle.com/#!3/f7fae/5/0