I have a SQL table that looks something like this:
OP
ID
First name
Last name
Phone number
I
123
John
Smith
888-555
U
123
777-555
I have to combine this rows through select query into something like this:
ID
First name
Last name
Phone number
123
John
Smith
777-555
I have trouble writing query because my only idea is with MAX, but sometimes is field from U row lesser than the one in I row and I need to check every column.
What I tried:
Select ID,
max('First name') as 'First name',
max('Last name') as 'Last name',
max('Phone number') as 'Phone number'
from table
group by ID
Please help.
You seem to want a priority, with U first then I. One method is to use coalesce() with conditional aggregation:
select id,
coalesce(max(case when OP = 'I' then first_name end),
max(first_name)
) as first_name,
coalesce(max(case when OP = 'I' then last_name end),
max(last_name)
) as last_name,
coalesce(max(case when OP = 'I' then phone_number end),
max(phone_number)
) as phone_number
from t
group by id;
You could use the JOIN keyword to join the two tables together with the max values included.
Here's a link to reference the code you're looking for: Select only rows by join tables max value
You can use an autoreferenced JOIN to search the not null rows and OP = I, to not depends of a MAX
SELECT a.OP, a.ID,
COALESCE(a.'First name',b.'First name'),
COALESCE(a.'Last name',b.'Last name'),
'Phone number'
FROM table a
LEFT JOIN (SELECT * FROM table WHERE OP = 'I' AND and 'First name' IS NOT NULL AND 'Last name' IS NOT NULL LIMIT 1) b ON b.ID = a.ID;
Related
I like to count the number of appearance of my users in more then one column. This is how I count the values in columns:
SELECT COUNT(col_01) FROM table_01 WHERE col_01 = 'John' // result: 2
SELECT COUNT(col_02) FROM table_01 WHERE col_02 = 'John' // result: 4
Is there any way to count John in one step in all columns I have and get the results 6?
Thank you in advance!
First filter the table so that you get only the rows with 'John' in any of the 2 columns and then use aggregate function TOTAL() on each column:
SELECT TOTAL(col_01 = 'John') + TOTAL(col_02 = 'John') AS total
FROM table_01
WHERE 'John' IN (col_01, col_02);
Try conditional aggregation
select
sum(case when col_01='John' then 1 end) +
sum(case when col_02='John' then 1 end)
from table_01;
I am trying to compare each row from a select statement to a reference row.
So to put it into context I would like to find the reference row which is the account details for one of our users.
SELECT id, first_name
FROM account
WHERE id = '100'
Would return the info for the user in question
Then I want to run a SELECT statement to return all users - pretty straightforward
SELECT id,first_name
FROM account
For each row I would like to compare the first_name with the reference row. If it is the same return a '1' if it is different return a '0'
I can do this if I type in the value to compare e.g 'Paul'
SELECT id,first_name,
CASE
WHEN first_name = 'Paul' THEN '1'
ELSE '0'
END
FROM account
But obviously I want to replace Paul with whatever the first_name is from the reference row above.
My googling suggests I need to declare a variable and then something with SELECT INTO a variable
DO $$;
Declare
#reference_first_name text;
BEGIN
SELECT first_name
into #reference_first_name
FROM account
WHERE id = ‘100’
END;
But I can't seem to put it together.
Then to go a step further would it be possible to reference multiple columns?
You could do this simply in a subquery:
demo:db<>fiddle
SELECT
id,
first_name,
CASE
WHEN (SELECT first_name FROM users WHERE id = 100) = first_name THEN 1
ELSE 0
END
FROM users;
Other ways are using a CTE or a JOIN (see fiddle for these versions)
Here's another option using an outer join:
select a.id, a.first_name, case when a.first_name = b.first_name then 1 else 0 end
from account a
left join account b on b.id = 100
Online Demo
Use correlated subquery as :
select a.id, a.first_name,
( select count(*)
from personnel p
where p.id = 100
and upper(p.first_name) = upper(a.first_name) ) as flag
from account a;
provided you have a table called personnel and has an ID fixed for all comparisons.
Rextester Demo
I have a column that gets generated using CAST(CASE WHEN A and B THEN SSS) as Name
Now I need another column which will use the value of the column above in the same way (CASE WHEN Name SSS THEN 123)
Is that possible?
UPDATE:
Example:
I have a table with
Name, Age, UserCode, UserId
I would like to generate a table using SELECT which includes
Name, UserCode, UserName
Name: returned from the column Name
UserCode:
CAST(CASE WHEN UserCode = 'A' and UserId = 'B' THEN 'SSS'
CASE WHEN UserCode = 'C' and UserId = 'Z' THEN 'ZAZ')
UserName: use the result from UserCode, so if UserCode is SSS then UserName become SAR123 etc...
Try this:
Select *,
CASE UserCode
When 'SSS' Then 'SAR123'
--When ... --<<Put other When clauses here
END AS UserName
FROM(
Select Name ,
CASE WHEN UserCode = 'A' and UserId = 'B' THEN 'SSS'
WHEN UserCode = 'C' and UserId = 'Z' THEN 'ZAZ'
END AS UserCode
From Table
) AS K
The alias of column name are obtained after the FROM, WHERE and then SELECT clause code evaluation .. so these alias are not available before this evalution is finished for this reason
alias of column name are not allowed in select or where clause and for these clause you must rewrite the code when need
select (CASE WHEN CAST(CASE WHEN A and B THEN SSS .....) SSS THEN 123 .... )
FROM my_table
.......
but alias for column name are available for ORDER BY and GROUP BY (clause that are evalueted after the previous mentioned)
alias of coulmn can be used in order by and group by
I have a set of postgreSQL data which looks like the one in the attached pic(Pic1-Sample Data) :
custom_field column would identify if the row entry is 'Department ID' or 'High Priority Role?' and the first six digits of text_value column would give the department codes.
As you can see value in the text_value column is 'Yes' wherever the custom_field is 'High Priority Role?'
Now my requirement is to extract only those records where custom_field is 'High Priority Role'. This sounds very simple but it should also have the 'Department ID' attached to it.
NOTE: job_id is not unique. Each job_id corresponding to 'High Priority Role?' would also have a duplicate entry for which the value in custom_field would be 'Department ID'(see attached Pic 2 for reference).
Something like this?
select
a.*,
b.display_value as department
from (
select
*
from
<table>
where
custom_field = 'High Priority Role?'
) a
inner join
<table> b
on
a.job_id = b.job_id
where
b.custom_field != 'High Priority Role?'
group by
a.job_id,
a.custom_field,
a.float_value,
a.date_value,
a.display_value,
a.text_value,
a.unit,
b.display_value
I've tested in MariaDB, not PostgreSQL, but it should work.
http://sqlfiddle.com/#!15/62ca4/3/0
This is a simple join:
select t.*, left(t2.text_value, 6) as department_id
from t join
t t2
on t.job_id = t2.job_id and
t.custom_field = 'High Priority Role?' and
t2.custom_field <> 'High Priority Role?';
This assumes that there is exactly one matching job with the department id.
If there are multiple, then go for a lateral join:
select t.*, left(t2.text_value, 6) as department_id
from t, lateral
(select t2.*
from t t2
where t.job_id = t2.job_id and
t.custom_field = 'High Priority Role?' and
t2.custom_field <> 'High Priority Role?'
fetch first 1 row only -- no `order by` because any match will do
) t2;
I am trying to write a query which needs to find an ID number from 3 WHERE values based on the result only being equal to 1.
So say i want to find a patient's ID and my where clause matches the firstname, lastname and DOB. If there are 2 results because of duplicates, i need the output to be NIL else it should return the patient ID.
if(select count(*)
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01') > 1
print 'NULL' else return Pat_ID1
This is kind of what i am leading towards.
Thanks guys
select case when count(*)> 1
then 'NULL' else Pat_ID1 end
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01'
group by Pat_ID1
try below.
;WITH CTE(Pat_ID1,last_name,first_name,birth_DtTM,dup_rows)
as
(
SELECT Pat_ID1,last_name,first_name,birth_DtTM,ROW_NUMBER() OVER(PARTITION BY last_name,first_name,birth_DtTM ORDER BY Pat_ID1) AS dup_rows FROM patient
)
SELECT
case when dup_rows>1 then null
when dup_rows=1 then Pat_ID1
end
FROM CTE
You can do it like this:
SELECT
PatientID = CASE COUNT(*) WHEN 1 THEN MAX(Pat_ID1) END
FROM
patient
WHERE
last_name = 'JAMES'
AND first_name = 'JONES'
AND birth_DtTM = '1980-01-01'
;
The CASE expression will evaluate either to the single Pat_ID1 matching the request or to NULL (if COUNT(*) is anything but 1).
As you can see, the Pat_ID1 value is obtained with the help of an aggregate function (by the way, you can use MIN instead of MAX just as well). This is because the presence of COUNT(*) in the query automatically implies grouping and now, if you want to reference columns of the underlying row set, you must only access their aggregated values.