Finding rows which match and blanks - mysql

I have a table of users and a table of electronic signatures - I want to be able to show for a given document who has signed and who has not.
Lets say we have employees:
EID Name
1 Bob
2 Tom
3 Fred
signatures:
EID Document Signature
1 1 Bob
1 2 Bob
1 3 Bob
2 1 Tom
3 2 Fred
My issue is that I can get this to work fine for document 4 - as no one has signed I can look where the document is null
However, if I look for document 2, for example, then I am currently getting employees missed off the list
For document 2 I would want to see
EID Signature
1 Bob
2
3 Fred
For document 4 I would want to see:
EID Signature
1
2
3
and for document 1:
EID Signature
1 Bob
2 Tom
3
The query I have tried to use is:
SELECT e.eid, s.signature
from employees e
left join signatures s on e.eid=s.eid
where s.document=? or s.document IS NULL group by e.eid

There are multiple issues:
Whenever using Left Join, any Where conditions on the right-side tables, should be put in the On clause. Otherwise, it will filter your result-set, even if there is no matching row (losing the purpose of Left Join)/
To compare null values, we use IS NULL. = null does not work. In this case, if we shift the conditions to On clause, we don't need to check for null values either.
Group By usage is invalid and really not required. When using Group By, only aggregated columns or the columns specified in Group By should come in Select. Refer: https://stackoverflow.com/a/41887524/2469308
Try the following:
SELECT e.eid, s.signature
FROM employees e
LEFT JOIN signatures s
ON e.eid=s.eid AND
s.document = ?

Related

How to count a null value as 0 while using JOINS in Mysql database?

I have 2 tables as follows
Human
id name
1 John
2 mark
Computer
id human_id
1 2
2 null
I want my answer to be as following
name no_of_computer
John 0
mark 1
I tried the following but am wrong
select h.name,c.human_id) as 'no_of_computer' from human h
join
computer c on c.human_id = h.id
group by h.id
my code is not counting the null as 0 so its just avoiding that and only showing that mark has 1 computer, but I want to see John has 0 computer too. please help me out, thanks in advance
You can use a subquery that's something like:
SELECT
h.Name,
(SELECT COUNT(c.id_of_computers)
FROM computers c
WHERE c.id_human = h.id) as no_of_computer
FROM humans h
Do not cut and paste this to test, as I paid no attention to actual ID names in your tables. You'll have to look at that. 👍

Select and compare two columns from different tables to find matched records

I'm just learning PHP and MySQL and I have two tables in the same database : FirstYear , SecondYear that have a structure like this :
StudentId |Math | Physics StudentId1 | Math1 | physics1
Joe 10 14 Alan 12 17
Alan 13 17 Smith 11 13
Smith 9 9 Joe 10 15
Is it possible to write a query that select and compare the two columns StudentId , StudentId1 to find matched records and if for example Joe=Joe after that compare records of math with math1 and physics with physics1 that are in the same row as matched records of StudentId with StudentId1 ;the idea of this query is to study the improvement of same student from first year to the second one ,Thanks .
Yes, it is possible but you have to complete SQL fundamental course.
In this situation you have to know about JOIN. Such as, Inner Join, Left Join, Right Join, Full Join etc. Also, compare with unique id, not name. Because, name always duplicate. It is not good practice. So, Know about primary key and foreign key.
However,
Query-
SELECT * FROM FirstYear INNER JOIN SecondYear ON FirstYear.StudentId = SecondYear.StudentId1 WHERE FirstYear.id = 1
Something like that, alternatively, you can try to another logic.

Duplicate or unpredictable results in MySQL

I'm trying to join a few tables in MySQL. Our setup is a little unique so I try to explain as good as I can.
I have a table 'INVENTORY' that represents the current items on stock.
These items are stored in a table 'COMPONENT'
Components are being used in installations.
Every user can have multiple installations and the same component can be used in multiple installation as well.
To uniquely map a component to an installation, it can be assigned to a PRODUCT. a product as has a 1-1 relationship with an installation. A component is not directly related to an installation
To finally assign a product to a specific installation a mapping table COMPOMENT_PRODUCT is used.
Example:
A component is like a part, lets say a screw. This screw is used in a computer. The very same screw can be used on multiple computers. But each computer can only be used on one specific installation.
TABLE COMPOMENT_PRODUCT
COMPOMENT_ID PRODUCT_ID
1 1
1 2
2 1
2 2
So we have the components C1 and C2 relevant for two installations.
TABLE INVENTORY
COMPOMENT_ID INSTALLATION_ID ON_STOCK
1 1 5
1 2 2
What I want to achieve
Now, I want to retrieve the inventory state for all components. But, not every component has an inventory record. In these cases, the ON_STOCK value from the inventory shall be NULL
That means, for this example I'd expect the following results
COMPOMENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 2
2 1 NULL
2 2 NULL
But executing this query:
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
returns the following resultset:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
1 1 2
1 2 2
2 1 (null)
2 2 (null)
Now, my next thought was, "of course, this is how joins behave, okay I need to group the results". But the way SQL works, the aggregation is not entirely predictable. SO when I
GROUP BY COMPONENT_PRODUCT.COMPONENT_ID,COMPONENT_PRODUCT.PRODUCT_ID
I get this result:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
2 1 (null)
2 2 (null)
I have prepared a Fiddle here: http://sqlfiddle.com/#!9/71ca87
What am I forgetting here? Thanks in advance for any pointers.
Try this query -
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
AND COMPONENT_PRODUCT.PRODUCT_ID = INVENTORY.INSTALLATION_ID

MySQL table comparison between two tables

I have two tables, follow and followed. I want to get all the rows in the follow table such that follow.screen != followed.following_screen_name.
follow table
ID screen_name
-----------------
1 eddie
2 jason
3 omar
4 jonathan
5 jack
followed table
ID my_screen_name following_screen_name
-------------------------------------------
1 john eddie
2 kenny eddie
3 kenny omar
4 john jason
5 john omar
Query I tried which didn't work
SELECT follow.screen_name from follow, followed where followed.my_screen_name='john'
AND follow.screen_name != followed.following_screen_name
Expected results
ID screen_name
-----------------
1 jonathan
2 jack
you can get this by doing a LEFT JOIN
SELECT F.screen_name FROM follow F
LEFT JOIN followed FD
on F.screen_name = FD.my_screen_name
OR F.screen_name = FD.following_screen_name
WHERE FD.my_screen_name IS NULL
and FD.following_screen_name IS NULL
Another way is to use NOT EXISTS, get all rows that exists in followed and do NOT EXISTS clause to get desired result.
SELECT F.screen_name FROM follow F
WHERE NOT EXISTS
(
SELECT 1 FROM followed FD
WHERE F.screen_name = FD.my_screen_name
OR F.screen_name = FD.following_screen_name
)
There are plenty of ways to solve this, but common to all is that you need to compare the follow.screen_name to both followed.my_screen_name and followed.following_screen__name.
One way is to use NOT IN with a UNION:
select screen_name
from follow
where screen_name not in (
select following_screen_name
from followed
where following_screen_name is not null
union all
select my_screen_name
from followed
where my_screen_name is not null
)
While this approach is nice for clarity, it may not be as good for performance as using a left join or not exists.
A nice place to pick up mysql syntax and logic is here.
But try this code, it selects every row where the screen_name is not identical to anything produced in the next two queries:
SELECT * from follow WHERE screen_name
not in (select screen_name from followed)
AND not in (select followed_screen_name from followed);
The last two queries would look this and the WHERE filters all of the rows out with screen names identical to the fields below.
my_screen_name following_screen_name
-------------------------------------
john eddie
kenny eddie
kenny omar
john jason
john omar

How do I use join to get a single result searching multiple rows on the join table?

I don't really know how to word this but I think an example would make this really easy. Lets say there is a database of students and classes.
Students:
id | name
1 | Bill
2 | Tom
Classes
id | name
1 | history
2 | math
3 | science
student_class
student_id | class_id
1 | 1
1 | 3
What I'm trying to do is get the query to return student Bill ONLY IF I search for classes 1 AND 3, right now I can get it to return Bill if I search for 1, 1 and 3, and 1, 2, and 3 using a normal left join. I'm trying to search from the students table and find results that only include all search terms listed. Something like:
SELECT * FROM students
LEFT JOIN studen_classes on students.id = student_classes.student_id
WHERE student_classes.class_id IN (1,3)
I've also tried
WHERE student_classes.class_id = 1 AND student_classes.class_id = 3
They both will return results if a student is attached to class 1 OR 3 when I want the results to only return students who have class 1 AND 3. Any ideas?
Put a HAVING clause in there, with appropriate GROUP BY and whatnot:
HAVING COUNT(student_class.class_id) = 2
That'll post-filter the query results to allow only those records where the count of class ID's is 2, meaning that they're in both the 1 and 3 classes. If they're in only one of the two, or none, their count would be 0 or 1.