Select from Column A based on Column B - sql

I have 4 tables joined together and this is the result of that query,
Name Year
Erin 2015
Erin NULL
Erin NULL
Sarah 2010
Peter 2011
The two columns are from two different tables. They both have an ID I can match. How do I narrow it down to this result,
Name Year
Erin 2015
Erin NULL
Erin NULL
When Year = 2015, I want all of Erin's.
SELECT Name
CASE WHEN Year = 2015 THEN
......
END
Rest of the columns I've selected
FROM Table
Joined with 4 other tables
WHERE
Stuff
What can I put in between the CASE statement.

It sounds like you want to see all the records from any name that has at least one record with a year = '2015'. If so, then:
SELECT Name, Year, Other_Columns
FROM Name N
JOIN YEAR Y on Y.ID = N.ID
WHERE N.ID IN (
SELECT ID
FROM YEAR
WHERE YEAR = '2015'
)

Put the same case when into the where clause:
select
case when .. then 'a' else 'b' end
from TABLE
where
(case when .. then 'a' else 'b' end) = 'b'
;

Related

Extract column from SQL table based on another column if the same table

I m using POSTGRESQL.
Table of PURCHASES looks like this:
ID | CUSTOMER_ID | YEAR
1 1 2011
2 2 2012
3 2 2012
4 1 2013
5 3 2014
6 3 2014
7 3 2015
I need to extract 'ID' of the purchase with the latest 'date/year' for each CUSTOMER.
For example for CUSTOMER_ID 1 the year s 2013 which correcponds with id '4'.
I need to get ONE column as a return data structure.
PS. i m stuck with this kinda simple task )))
If you want one row per customer, you can use distinct on:
select distinct on (customer_id) id
from purchases
order by customer_id, year desc;
This returns one column which is an id from the most recent year for that customer.
This should work, but doesn't look too pretty...
SELECT DISTINCT ON(CUSTOMER_ID) ID FROM PURCHASES P
WHERE (CUSTOMER_ID,YEAR) =
(SELECT CUSTOMER_ID,MAX(YEAR) FROM PURCHASES WHERE CUSTOMER_ID = P.CUSTOMER_ID
GROUP BY CUSTOMER_ID);
So for input
ID | CUSTOMER_ID | YEAR
1 1 2011
2 2 2012
3 2 2012
4 1 2013
5 3 2014
6 3 2014
7 3 2015
It will return
id
4
2
7
Meaning:
For the lowest CUSTOMER_ID (it is 1) the id is 4 (year 2013)
Next we have CUSTOMER_ID (it is 2) the id is 2 (year 2012)
Lastly the CUSTOMER_ID (it is 3) the id is 7 (year 2015)
The idea behind this:
Group by CUSTOMER_ID
For each group select max(year)
While looping over all records - if Customer_id and year equals those from number 2. then select ID from this record.
Without DISTINCT ON(CUSTOMER_ID) it would return 2 records
for CUSTOMER_ID = 2, because for both years 2012 it would find some records while looping.
If you write in the beginning instead of:
SELECT DISTINCT ON(CUSTOMER_ID) ID FROM PURCHASES P
this code:
SELECT DISTINCT ON(CUSTOMER_ID) * FROM PURCHASES P
then you will see everything clearly.
Use row_number() analytic function with partition by customer_id to select by each customer with descending ordering by year ( if ties occur for year values [e.g. they're equal], then the below query brings the least ID values for each customer_id. e.g. 4, 2, 7 respectively )
WITH P2 AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY YEAR DESC) AS RN,
*
FROM PURCHASES
)
SELECT ID FROM P2 WHERE RN = 1
Demo

Postgres SQL GROUP BY depending on a value from another column

I am trying to query set result set which returns something like the below.
I need to return only 1 row per name and need to GROUP BY but only the name that have a value of '8' under the Grade column are desired. The below is a result from another query. Because Sandra has a different value other than 8, Sandra should be omitted.
eg:- In the below I need to get one row for John only.
Please advise. Thank you.
Name Grade
======= =====
Sandra 8
Sandra 8
Sandra 8
Sandra 9
John 8
John 8
John 8
John 8
Expected Result - 1 row
Name Grade
John 8
Aggregate your table on the name, and then use a HAVING clause to filter out names which have a grade other than 8 (or any other values which you do not want).
SELECT name, MIN(grade) AS grade
FROM yourTable
GROUP BY name
HAVING SUM(CASE WHEN grade <> 8 THEN 1 ELSE 0 END) = 0;
Demo
Update:
If the grade column were text, and you wanted to compare against the string '8' instead of a number, then you could use this HAVING clause:
HAVING SUM(CASE WHEN grade <> '8' THEN 1 ELSE 0 END) = 0;
If you want names that have only 8s, you can do:
select name
from t
group by name
having min(grade) = max(grade) and min(grade) = 8;
Alternately,
SELECT DISTINCT B.name, B.grade
FROM
(
SELECT name FROM yourTable GROUP BY name HAVING COUNT(DISTINCT grade) = 1
) Z
INNER JOIN
yourTable B
ON Z.name = B.name
AND B.grade = 8;

SQL find total count of each type in a column

I'm learning SQL and am stumped on what should be a simple query. I have a table with the following pattern:
Id | Type
------------
1 | Red
2 | Blue
3 | Blue
4 | Red
..
I would like to write a query to return a table that counts the total number of instances of each type and returns a table with the following pattern, for example, if 'Blue' occurs in 12 rows, and 'Red' occurs in 16 rows in the table above, the result would be:
Blue | Red
-----------
12 | 16
You could do it this way:
SELECT Type, COUNT(*) FROM TABLE GROUP BY Type
If you'd like to see the Types in separate columns, you could do this:
SELECT SUM(CASE WHEN Type = 'Blue' THEN 1 ELSE 0 END) AS Blue, SUM(CASE WHEN Type = 'Red' THEN 1 ELSE 0 END) AS Red FROM TABLE
I suggest using count over partition by. Here's a code I wrote to help my company check for duplicate Technician EmployeeID's and Pincodes, including count and YES/NO columns to allow filtering in excel so they can see what corrections need to be made:
select
t.TechnicianId, t.TechnicianName, t.Pincode, t.EmployeeID
, [Pincode Count] = count(t.Pincode) over (partition by t.Pincode)
, [Duplicate Pincode?] = case count(t.Pincode) over (partition by t.Pincode) when 1 then 'NO' else 'YES' end
, [EmployeeID Count] = count(t.EmployeeID) over (partition by t.EmployeeID)
, [Duplicate EmployeeID?] = case count(t.EmployeeID) over (partition by t.EmployeeID) when 1 then 'NO' else 'YES' end
from Technicians t
group by t.TechnicianId, t.TechnicianName, t.Pincode, t.EmployeeID
order by 4

Sql Grouping Query

I'm wondering how i can get a query to put these groupings into one line so i can put it into a vb.net datagrid.
For example Number, Company Name, Current, 31-60, 61-90
Which would be for example company A, but get the grouping to all be on one line.
104680777, Company A, 643546.344, 34534534.77, 3454.55
To even get this query below. I had to do this.
select sum(Amount), DunsNum, CompanyName, Age
from tblARAged
group by DunsNum, Age, CompanyName
Amount Num CompanyName Age
63546.344 104680777 Company a 1
34534534.77 104680777 Company a 2
3454.55 104680777 Company a 3
3453453.66 186830733 Company b 1
345342.45 186830733 Company b 2
4542.55 186830733 Company c 3
3434.55 26409797 Company c 1
345345 26409797 Company c 2
The 1 correlates to current, 2 correlates to 31-60 and 3 correlates to 61-90 for age
I would do what Nimesh stated, though I would make a few tweaks. You want to do aggregation as late as possible:
SELECT DunsNum ,
CompanyName ,
SUM(CASE WHEN ( Age = 1 ) THEN Amt
ELSE 0
END) AS [Amount_Cur] ,
SUM(CASE WHEN ( Age = 2 ) THEN Amt
ELSE 0
END) AS [Amount_31-60] ,
SUM(CASE WHEN ( Age = 3 ) THEN Amt
ELSE 0
END) AS [Amount_61-90]
FROM tblARAged
GROUP BY DunsNum ,
CompanyName;
I haven't tested this code

Sql Result two columns

I have the following table:
Full name status
ricardo 1 2
ricardo 2 4
How do I make a select to return like this:
name totalstatus1 totalstatus2 total
ricardo 2 4 6
You did not include the name of the column with the 2 and 4 but you could use something similar to this:
select name,
sum(case when status = 1 then value end) totalStatus1,
sum(case when status = 2 then value end) totalStatus2,
sum(value) Total
from yourtable
group by name;
See SQL Fiddle with Demo