SQL logical not equals - mysql

I know this is a logic problem, however I am fairly new to SQL and do not know how to get through this one:
I have two tables.
Table A has a distinct ID.
Table B is used to store bits of data pertaining to any row in Table A.
Table B may have multiple rows which reference a single row of Table A.
How can i search for all of A's ID's in table B for which a single row of B does not equal a certain value?
SELECT DISTINCT table_a_id FROM table_b b WHERE b.meta_key != 'hidden'
since table_a_id is not distinct, this will return table_a_id's as long as the only row in table B for that particular table_a_id is not 'hidden'. Obviously it works if i am looking for each table_a_id which is hidden (if I use = instead of !=), but how do I accomplish the opposite?
Thanks

One method is to use group by with a having clause:
SELECT table_a_id
FROM table_b b
GROUP BY table_a_id
HAVING SUM(b.meta_key = 'hidden') = 0;
An alternative is to use not exists:
select a.id
from table_a a
where not exists (select 1
from table_b b
where a.id = b.table_a_id and b.meta_key = 'hidden'
);
This version actually has the advantage that it will show all rows from table_a, even when there are no rows in table_b. The first version will only show ids that have some data in table_b, just not the 'hidden' values.

Related

SQL: How to check for each row in Table A if there is a relationship with each row in Table B

I have three tables.
TABLE A
A_ID
TABLE B
B_ID
JOIN TABLE
A_ID
B_ID
For every row in TABLE A, I am trying to check whether or not it is connected to TABLE B in JOIN TABLE.
Ideally, the output I'm trying to get back looks something like this:
...
Is this possible with SQL?
This is a variation of a common pivot-table solution for MySQL called conditional aggregation.
SELECT A_ID,
COALESCE(MAX(CASE B_ID WHEN 1 THEN TRUE END), FALSE) AS TABLE_B_ENTRY_1,
COALESCE(MAX(CASE B_ID WHEN 2 THEN TRUE END), FALSE) AS TABLE_B_ENTRY_2
FROM TABLE_A
LEFT OUTER JOIN JOIN_TABLE USING (A_ID)
GROUP BY A_ID;
You do have to explicitly code a column expression for each distinct value of B_ID you want to search for. There's no way in SQL to make a query that automatically expands the number of columns based on the data read in the same query.

Return rows from MYSQL table A where table_A.col_1 = table_b.col_2 without using a left outer join?

In a MySQL database with two tables table_A and table_B I want to return selected row columns from table_A based on comparison with values in table_B. The below erroneous line sums up the idea:
SELECT col_1, col_2, col_3 FROM table_A where table_A.col_1 = table_B.col_2;
I do not want any elements from table_B.
Why I can't use a left outer join: I've tried this with a left outer join as illustrated here(https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/) however the database complains that the column names are ambiguous and changing table column names in the database isn't an option.
I you want rows in table_A whose col1 can be found in table_B(col_2), you can use exists:
select a.col_1, a.col_2, a.col_3
from table_A a
where exists (select 1 from table_B b where b.col_2 = a.col_1);
If you want rows that do not exist in table_B, then just change exists to not exists.
Note that I prefix the column names with the (alias of the) table they belong to. This is called qualifying the columns, and is how you avoid the ambiguous column name problem that you seemingly have met when trying to join.
If column names are ambiguous, qualify them, eg
select table_A.col_1, table_A.col_2, table_A.col_3
from table_A
join table_B on table_A.col_1 = table_B.col_2
or for brevity you can assign an aliases to tables:
select a.col_1, a.col_2, a.col_3
from table_A a
join table_B b on a.col_1 = b.col_2

Update a field in table A with the max value of field in table B

I want to update a field, let's call it 'field_A', in table 'table_A' with the maximum value that exists of field 'field_B' in 'table_B', but only IF there is a max value for that field 'field_B' in table 'table_B'.
Table 'table_B' has a 'reference' field which contains the 'id' of the table_A record we want to update.
Now I have the following query, which works perfectly.
UPDATE table_A a SET a.field_A = (SELECT MAX(b.field_B)
FROM table_B WHERE b.reference = a.id)
WHERE a.id IN (
SELECT reference
FROM table_B
GROUP BY reference
HAVING COUNT(reference) > 0
)
So it only updates field_A IF there are records found for that reference because I don't want to end up setting fields 'field_A' to zero when no related records were found.
As I said before, this query already works perfectly, but now I have to run a query for table_B two times, which seems a little bit inefficient and it is probably possible to do it with only 1 join statement but I can't seem to tackle the issue.
Since this query has to cross reference a lot, really a lot, of records, performance is really an issue here.
With these two nested statements, your UPDATE statements seems quite
inefficient to me. Try this SQL statement below, that should do the job.
SQL Fiddle here: http://sqlfiddle.com/#!2/5825a/2
UPDATE table_A a1
JOIN
(
SELECT a.id as id, max(b.field_B) as max_val
FROM
table_A a
LEFT JOIN table_B b ON a.id = b.reference
GROUP BY a.id
) t on a1.id = t.id
SET
a1.field_A = t.max_val
WHERE
(t.max_val IS NOT NULL)

mysql multiple NOT in where condition based on result from another query

I have a situation where in i need to pull data from one table but exclude some rows based on the rows in another table. I mean that i need to pull studentid(s) from one table but exclude those studentid(s) which are there in another table.
first query :
$sql = "select studentid from table 2 where iarsid = '12'";
as i'll get an array result from this query i want to use this result and put it in NOT conditions in the next query simply excluding these very rows from the result from this another query.
Second query:
$sql2 = "select studentid from table 2, table 3 where iarsid = '12' // and a lot of joins";
Basically the students who are in the first table are not needed while pulling out students based on the second query.
If i am using the wrong logic, please guide so as to achieve this.
You can do the general idea at least 3 ways, using a LEFT JOIN, and also using NOT IN and NOT EXISTS.
Via LEFT JOINS.
SELECT student_name
FROM table_A a
LEFT JOIN table_B b ON a.student_id = b.student_id
WHERE b.student_id IS NULL
This gets all student information in table_A, where the student is not in table_B.
and here it is via NOT EXISTS:
SELECT student_name
FROM table_A a
WHERE NOT EXISTS (SELECT student_id FROM table_B b WHERE b.student_id = a.student_id)
and via NOT IN
SELECT student_name
FROM table_A a
WHERE a.student_id NOT IN (SELECT student_id FROM table_B b)
Do you mean second query that use the first query as a condition with NOT?
"select studentid from table 2, table 3 where iarsid = '12' // and a lot of joins"
+ " WHERE studentid NOT IN (select studentid from table 2 where iarsid = '12')"
I can see that you have accepted an answer. But you can also do this. The best way to check which query is fast by checking your Explain Plan.
SELECT student_name
FROM table_A a
WHERE a.student_id NOT EXISTS (SELECT student_id FROM table_B b)
Since this is an un-correalted query using exists, this will be fater for a larger table. And IN will be faster for a small table. The reason it's faster the moment it finds no match, it will return a false instead IN will do a full table scan.
Also this one:
SELECT student_name
FROM table_A a
WHERE NOT EXISTS (SELECT null
FROM table_B b
WHERE a.studentid = b.studentid);

Transforming a Complicated Requirement into a SQL Query

I am having trouble with the relational algebra and transformation into SQL of this rather complicated query:
I need to select all values from table A joined to table B where there are no matching records in table B, or there are matching records but the set of matching records do not have a field that contains one of 4 of a possible 8 total values.
Database is MySQL 5.0... using an InnoDB engine for the tables.
Select
a.*
from
a
left join
b
on
a.id=b.id
where
b.id is null
or
b.field1 not in ("value1","value2","value3","value4");
I'm not sure if there is any real performance improvement but one other way is:
SELECT
*
FROM
tableA
WHERE
id NOT IN ( SELECT id FROM tableB WHERE field1 NOT IN ("value1", "value2"));
Your requirements are a bit unclear. My 1st interpretation is that you only want the A columns, and never more than 1 instance of a given A row.
select * from A where not exists (
select B.id
from B
where B.id=A.id
and B.field in ('badVal1','badVal2','badVal3','badVal4')
)
My 2nd interpretation is you want all columns from (A outer joined to B), with perhaps more than one instance of an A row if there are multiple B rows, as long as not exists B row with forbidden value.
select * from A
left outer join B on A.id=B.id
where not exists (
select C.id
from B as C
where A.id=C.id
and C.field in ('badVal1','badVal2','badVal3','badVal4')
)
Both queries could be expressed using NOT IN instead of correlated NOT EXISTS. Its hard to know which would be faster without knowing the data.