SQL COUNT conditional on the results another table - sql

I am new to SQL and I'm having hard time with this scenario.
Table 1 contains information when a player was on a team.
Table1
playerID | yearID
----------------------
Player1 | 2000
Player1 | 2001
Player2 | 2000
Table 2 contains ballot information with the Hall of Fame. A player can be on multiple times.
playerID | BallotYear | Inducted
---------------------------------
Player1 | 2010 | N
Player1 | 2011 | N
Player2 | 2010 | Y
I am trying to count how many times a player shows up on Table1 conditional on them never being inducted based on Table2.
Desired Result
playerID | Count on Table 1
---------------------------
Player1 | 2
The issue I have come across is that Player1 returns 4, instead of 2. I have looked into a number of different functions, but I keep getting the same results. This is what I have come up with.
select Table1.playerID, count(Table1.playerID)
from Table1
join Table2 on Table1.playerID = Table2.playerID
where Table2.inducted = 'N'
group by Table1.playerID;

If I understand correctly, you want to filter out players that have ever had a 'Y' in the inducted field. If so:
select t1.playerId, count(*)
from table1 t1
where not exists (select 1
from table2 t2
where t2.playerID = t1.playerID and t2.inducted = 'Y'
)
group by t1.playerId;

You can achieve this using Left join which will also add to performance of query
select t1.playerId, count(*)
from table1 t1 left join
(select distinct playerID
from table2
where inducted = 'Y'
) t2 on t1.playerID = t2.playerID
where t2.playerId is null
group by t1.playerId

Related

SQL - How to pick the best available value for each column for each ID from multiple tables?

I have two tables with the same variables referring to attributes of a person.
How can I combine data from two such tables picking the best available value for each column from each table for each field?
Requirements:
For each field, I would like to fill it with a value from either one of the tables, giving a preference to table 1.
Values can be NULL in either table
In the combined table, the value for column 1 could come from table 2 (in case table 1 is missing a value for that person) and the value for column 2 could from table 1 (because both tables had a value, but the value from table 1 is preferred).
In my real example, I have many columns, so an elegant solution with less code duplication would be preferred.
Some users may exist in only one of the tables.
Example:
Table 1:
user_id | age | income
1 | NULL| 58000
2 | 22 | 60000
4 | 19 | 35000
Table 2:
user_id | age | income
1 | 55 | 55000
2 | 19 | NULL
3 | 22 | 33200
Desired output:
user_id | age | income
1 | 55 | 58000
2 | 22 | 60000
3 | 22 | 33200
4 | 19 | 35000
I think that's a full join and priorization logic with colaesce():
select user_id,
coalesce(t1.age, t2.age) as age,
coalesce(t1.income, t2.income) as income
from table1 t1
full join table2 t2 using(user_id)
Use full outer join if user_id in each table is unique.
SELECT
COALESCE(t1.user_id, t2.user_id) AS user_id,
GREATEST(t1.age, t2.age) AS age,
GREATEST(t1.income, t2.income) AS income
FROM t1
FULL OUTER JOIN t2 ON t1.user_id = t2.user_id
try like below using coalesce()
select t1.user_id, coalesce(t1.age,t2.age),
t1.income>t2.income then t1.income else t2.income end as income
table1 t1 join table2 t2 on t1.usesr_id=t2.user_id
You can use below code:
With TableA(Id,age,income) as
( --Select Common Data
select table_1.id,
--Select MAX AGE
case
when table_1.age> table_2.age or table_2.age is null then table_1.age else table_2.age
end,
--Select MAX Income
case
when table_1.income>table_2.income or table_2.income is null then table_1.income else table_2.income
end
from table_1 inner join table_2 on table_2.id=table_1.id
union all
-- Select Specific Data of Table 2
select table_2.id,table_2.age,table_2.income
from table_2
where table_2.id not in (select table_1.id from table_1)
union all
-- Select Specific Data of Table 1
select table_1.id,table_1.age,table_1.income
from table_1
where table_1.id not in (select table_2.id from table_2)
)select * from TableA

Update column with specific values ( if clause)

I am trying to insert new values into specific column with "update table set specific column...."
I have two tables like this:
Table1
Name Idnumber Score
JOHN DB 10
JOHN IT NULL
KAL DB 9
HENRY KK 7
KAL DB 10
HENRY IP 9
ALI IG 10
ALI PA 9
Table2
NAME | MONEY |
-----------------|
JOHN | |
-----------------|
KAL | |
-----------------|
HENRY | |
-----------------|
ALI | |
-----------------
And I want that my table look like this:
Updated Table
NAME | MONEY |
-----------------|
JOHN | |
-----------------|
KAL | yes |
-----------------|
HENRY | half |
-----------------|
ALI | yes |
-----------------
The condition for writing "yes" into money column is that all scores under same name in table1 should be 9 or higher, the condition for writing "half" is that scores should be no lower than 6 ( what I mean is that scores might be 10,9,8,7 and 6)
So basically it means, that, for example, Henry cannot be selected and I cannot write "yes" next to his name in updated table, because he has score under the value of 9 in one line , but in the other he has the score of 7.(null values also should be emitted).
I'm using a sas program. Thank you!!!
You seem to be treated NULL as a value that is less than "9". In standard SQL (which works in both MySQL and SAS, the original tags) is:
update table2 t2
set money = 'YES'
where not exists (select 1
from table1 t1
where t1.name = t2.name and coalesce(t1.score, 0) < 9
);
If you want to guarantee that there is at least one row in table2, one method is aggregation:
update table2 t2
set money = 'YES'
where (select (case when sum(case when t1.score > 9 then 1 else 0 end) = count(*)
then count(*)
end)
from table1 t1
where t1.name = t2.name
) > 0
You could try the following syntax:
update table2
set money = 'YES'
where not exists (select 1 from table1 t1 where t1.name = table2.name and t1.score < 9)
However this would also update records that have no match in table1. In MySQL, one simple option to avoid that uses a join:
update table2 t2
inner join (select name, min(score) min_score from table1 group by name) t1
on t1.name = t.name and t1.min_score >= 9
set t2.money = 'YES'

MS SQL Where one column is x or y and both returned

I have a table as follows with dates in. The table has many more records but simplified for asking purposes:
Name | Date | Grade
Person 1 | 01-01-2001 | B
Person 1 | 31-01-2001 | A
Person 2 | 01-01-2001 | C
Person 3 | 31-01-2001 | A
I want to return both records for Person 1 but not either of the other two. AND returns nothing obviously and OR returns everything. I want to search on the date not the grade or the person.
So the result would be:
Name | Date | Grade
Person 1 | 01-01-2001 | B
Person 1 | 31-01-2001 | A
One simple way to handle this is to aggregate by person and then assert that the two dates of interest are both present:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT Name
FROM yourTable
WHERE Date IN ('2001-01-01', '2001-01-31')
GROUP BY Name
HAVING COUNT(DISTINCT Date) = 2
) t2
ON t1.Name = t2.Name
You can uses EXISTS to return a row if there exists another row with that name, having the other A/B grade.
select t1.*
from tablename t1
where t1.Date in ('2001-01-01', '2001-01-31')
and exists (select 1 from tablename t2
where t2.Name = t1.Name
and t2.Date in ('2001-01-01', '2001-01-31')
and t2.Date <> t1.Date)

Select distinct values in same column by group

Using Microsoft Access and having a hard time figuring out how to get the desired results. I have two linked tables with an inner join on [bed] with the following data in both tables. I am looking to select [room number] that has a [gender] mismatch (has more than one distinct value per room number). I have searched stackoverflow and haven't found anything that seems to both group AND select distinct by group [room number].
Table 1
-----------------
Room Number | Bed
101 | 101a
101 | 101b
101 | 101c
102 | 102a
102 | 102b
103 | 103a
103 | 103b
Table 2
-----------------
Bed | Gender
101a | Male
101b | Male
101c | Female
102a | Male
102b | Male
103a | Female
103b | Undefined
With this data set, I would expect it to return Room 101 and 103 with the associated genders.
SQL Query
SELECT ROOM_NO
FROM RMGT_T_ROOMS INNER JOIN RMGT_T_ROOM_CONFIGS ON RMGT_T_ROOMS.PK_BED_SPACE = RMGT_T_ROOM_CONFIGS.CK_BED_SPACE
GROUP BY RMGT_T_ROOMS.FK_ROOM_NO
HAVING COUNT(DISTINCT GENDER) > 1
You could join that table on the bed's id and count the distinct number of genders:
SELECT room_number
FROM t1
JOIN t2 ON t1.bed = t2.bed
GROUP BY room_number
HAVING COUNT(DISTINCT gender) > 1
How about inner join and group by?
select t1.room
from t1 inner join
t2
on t1.bed = t2.bed
group by t1.room
having min(gender) <> max(gender);
If you know there are two genders only, you can add min(gender) and max(gender) to the select.
Another method uses exists:
select t1.room, t2.gender
from t1 inner join
t2
on t1.bed = t2.bed
where exists (select 1
from t1 as t11 inner join
t2 as t22
on t11.bed = t22.bed
where t22.gender <> t2.gender
);

Count similar records

How do I write an SQL showing the number of films member 1 and 2 have in common?
MID=Member ID
FID=Film ID
Explanation of table below: Member 1 has films 2,3,5,17,21 on his list. Member 2 has films 5,14,18 on his list.
1. MID ------ | FID
2. M000001 | F000002
3. M000001 | F000003
4. M000001 | F000005
5. M000001 | F000021
6. M000002 | F000005
7. M000002 | F000014
8. M000002 | F000018
9. M000003 | F000001
10. M000003 | F000004
11. M000003 |F000024
*sorry for the poor table.
If you want the number for all pairs, just do a self join:
select t1.mid, t2.mid, count(*)
from table as t1 inner join
table as t2
on t1.fid = t2.fid and t1.mid < t2.mid
group by t1.mid, t2.mid;
If you want to limit this just to two members, you can do:
select count(*)
from table as t1 inner join
table as t2
on t1.fid = t2.fid and
t1.mid = 1 and
t2.mid = 2;
With a subquery is one way.
SELECT COUNT(*) FROM t1 t
WHERE EXISTS (SELECT 1 FROM t1 WHERE Mid = 2 AND Fid = t.Fid)
AND Mid = 1