'IF' in 'FROM' statement - choose table value based on column value - mysql

SELECT CI FROM users WHERE something;
IF users.CI='pc' THEN
SELECT name FROM table1 WHERE something;
ELSE IF users.CI='ph' THEN
SELECT name FROM table2 WHERE something;
END IF
I know that doesn't work, but is an example to understand.
It's possible all of this in one query ?

SET #var = (SELECT CI FROM users WHERE something);
SELECT
CASE #var
WHEN 'pc' THEN
(SELECT name FROM table1 WHERE something)
WHEN 'ph' THEN
(SELECT name FROM table2 WHERE something)
END;

You cannot use IF ... THEN in a SQL query.
The solution is to left outer join both tables, letting the optimizer choose which table will be used by specifying so in the ON clauses.
You didn't explain what "something" was, so in this example, I am going to assume that "users" has an "id" column and that table1 and table2 have a "user_id" column, and that you are interested in the user with id = 1.
SELECT COALESCE(t1.name,t2.name) AS name
FROM users u
LEFT JOIN table1 t1 ON u.CI = 'pc' AND t1.user_id = u.id
LEFT JOIN table2 t2 ON u.CI = 'ph' AND t2.user_id = u.id
WHERE u.id = 1;

Related

Mysql get missing values from other table

I have below query which will give me the ID which is in both the table.
SELECT DISTINCT IP.id
FROM `table2` IR LEFT JOIN
(SELECT id
FROM table1
WHERE item='xyz'
ORDER BY Id limit 728,91
)
AS IP on IP.id = IR.id
where IR.item='xyz'
AND IR.idr='2295'
Now I need the missing ID from table2 which exist in table 1.
You need an outer join that works the other way round. Also, you don't need a sub query. The following query will return those id in table1 that have the desired item value and for which there is no record in table2 that has the same id and certain item and idr values.
select distinct ip.id
from table1 ip
left join table2 ir
on ir.id = ip.id
and ir.item = 'xyz'
and ir.idr = '2295'
where ip.item = 'xyz'
and ir.id is null
order by ip.id
limit 728, 91
NB: If you want to also add to that the id values that exist in both table1 and table2 (with the given conditions) then there is no reason to (outer) join table2 at all.

MySQL if statement on left join

I'm rewriting old code that returns data, and related attribute data.
The psudo logic of the old code:
SELECT * FROM Table;
foreach records
if record.col1 == '1'
SELECT * FROM Table1;
SELECT * FROM Table2;
elsif record.col1 == 'A'
SELECT * FROM TableA;
SELECT * FROM TableB;
In the example below ( excuse my crude E.R.D ), Table has a One-to-one relationship with either Table1 & TableA, separately.
Table1 has a One-to-many relationship to Table2.
TableA has a One-to-many relationship to TableB.
[ Table ] --- [ Table1 ] --< [ Table2 ]
[ Table ] --- [ TableA ] --< [ TableB ]
I'm wrting a procedure to return all rows of Table, along with additional data from its relationships, if available.
I've managed to achieve the first example relationship using LEFT JOIN
SELECT Table.col1, Table.col2, Table1.*, Table2.*
FROM Table
LEFT JOIN Table1
ON Table1.col3 = Table.col3
AND Table1.col4 = Table.col4
AND Table1.col1 = Table.col5
LEFT JOIN Table2
ON Table1.col1 = Table2.col6
What i'm stuck with now is how to phrase an IF style using a JOIN of some type. I've used LEFT JOIN as i wish for all rows from Table, and only matching rows from Table1 & Table2.
In my head i've got somthing like
SELECT Table.col1, Table.col2, Table1.*, Table2.*
FROM Table
IF Table.col1 = '1'
LEFT JOIN Table1
ON Table1.col3 = Table.col3
AND Table1.col4 = Table.col4
AND Table1.col1 = Table.col5
LEFT JOIN Table2
ON Table1.col1 = Table2.col6
ELSE Table.col1 = 'A'
LEFT JOIN TableA
ON TableA.col3 = Table.col3
AND TableA.col4 = Table.col4
AND TableA.col1 = Table.col5
LEFT JOIN Table2
ON TableA.col1 = TableB.col6
The above is invalid, but thats my current mind set. Could i potentially use a UNION, and include a WHERE Table.col1 = '?' on each side of the union?

Update of single table using join

I have a select using two tables via a join. I need to update first table using the second table field. Select as follows
select R.f1, Z.f2,R.f3
FROM
(select * From Table1 where f2<>'xx' and f3='z') R inner join
(select * From Table2 where f3='xx') Z
ON R.f1⁼Z.f1 and R.f4=Z.f4
How could I update correspond to same select of Table1 (SET R.f2=Z.f2)?
UPDATE
(select * From Table1 where f2<>'xx' and f3='z') R inner join
(select * From Table2 where f3='xx') Z
ON R.f1⁼Z.f1 and R.f4=Z.f4
SET R.f2=Z.f2
When I tried, I get a response that
target table R of the UPDATE is not updatable
You can use a join in update statements using the following....
update t
set t.Column = value
from Table t
inner join OtherTable ot on t.Id = ot.TID
where somecondition = true.
You should perform the update on table1 and join it to the second subquery. The conditions on table1 from the first subquery could be applied in the where clause:
UPDATE table1 r
JOIN (SELECT * FROM table2 WHERE f3 = 'xx') z ON r.f1 ⁼ z.f1 AND r.f4 = z.f4
SET r.f2 = z.f2
WHERE r.f2 <> 'xx' AND r.f3 = 'z'

MySQL: GROUP_CONCAT where rows may not exist

I have 3 tables: table1, table2 & table3
I make a select query from table1 which LEFT JOINS the other two tables. In the select I have a group_concat which takes a value from table3. Everything works well until a row with a specific row doesn't exist. The group_concat list becomes empty. Instead, I would like it to set values in the group_concat to NULL for the ones where the rows doesn't exist.
Like I said if the value in table3 exist for all the rows in table2 then it works. If not, the whole group_concat is empty.
Some "simplified" code of what I got so far:
SELECT
table1.table2Id,
table1.dateAdded,
IF(COUNT(table2.table3Id) = COUNT(*), GROUP_CONCAT(table2.table3Id), NULL) as group1,
IF(COUNT(table3.ext) = COUNT(*), GROUP_CONCAT(table3.ext), NULL) as group2
FROM table1
LEFT JOIN table2 ON
table2.id = table1.table2Id
LEFT JOIN table3 ON
table3.id = table2.table3Id
Fixed it by changing
IF(COUNT(table3.ext) = COUNT(*), GROUP_CONCAT(table3.ext), NULL) as group2
to
GROUP_CONCAT(IFNULL(table3.ext, NULL)) as group2
In your situation when you are using joins use derieved sub query in join and use IFNULL and set its default value to 0 then in the outer table this value (0) will be used if there comes null.
EDITS :
as there is no data to test you can do it like this. Use INNER JOIN instead of left join.
SELECT
table1.table2Id,
table1.dateAdded,
IF(COUNT(table2.table3Id) = COUNT(*), GROUP_CONCAT(table2.table3Id), NULL) as group1,
IF(COUNT(table3.ext) = COUNT(*), GROUP_CONCAT(table3.ext), NULL) as group2
FROM table1
INNER JOIN table2 ON
table2.id = table1.table2Id
INNER JOIN table3 ON
table3.id = table2.table3Id
Also try using derieved sub query
SELECT
table1.table2Id,
table1.dateAdded,
IF(COUNT(t2.table3Id) = COUNT(*), GROUP_CONCAT(t2.table3Id), NULL) as group1,
IF(COUNT(table3.ext) = COUNT(*), GROUP_CONCAT(table3.ext), NULL) as group2
FROM table1
LEFT JOIN (
SELECT
id,
IFNULL(table3Id,0) as table3Id,
table3Id
FROM table2
GROUP BY id table3Id
)as t2 ON t2.id = table1.table2Id
INNER JOIN table3 ON table3.id = t2.table3Id

complex sql statement to different rows

I have a simple table which has 4 fields:
indexID
UserID
text_1
IsFinal
This table may have multiple values for each UserID, and IsFinal field can have only a single value 1 or 0.
What I'm trying to do is to make a select statement which will return the user IDs if IsFinal only equal 0. The problem there may be multiple records for the same userID, some having IsFinal equal to 0 and only 1 with IsFinal equal to 1.
My problem here is this: for every UserID, if it has a record with Isfinal = 1, I want to ignore all records with the same UserID, otherwise I want to return its records. I don't know if that can be done by SQL statement only or not.
Seems like you want an anti-join, i.e. you first need to establish which user IDs have IsFinal = 1, then use that result set to return all user IDs not in that list.
There are various ways to implement an anti-join.
NOT IN:
SELECT *
FROM atable
WHERE UserID NOT IN (
SELECT UserID
FROM atable
WHERE IsFinal = 1
);
NOT EXISTS:
SELECT *
FROM atable t1
WHERE NOT EXISTS (
SELECT *
FROM atable t2
WHERE t1.UserID = t2.UserID
AND t2.IsFinal = 1
);
LEFT JOIN + WHERE IS NULL:
a)
SELECT *
FROM atable t1
LEFT JOIN (
SELECT *
FROM atable
WHERE IsFinal = 1
) t2 ON t1.UserID = t2.UserID
WHERE t2.UserID IS NULL;
b)
SELECT *
FROM atable t1
LEFT JOIN atable t2
ON t1.UserID = t2.UserID AND t2.IsFinal = 1
WHERE t2.UserID IS NULL;
It may so happen that they will be equally efficient in your database, but it still may be a good idea to test each of them to at least avoid ending up with one that performs worse than the others.
I think this is what you are looking for:
SELECT a.*
FROM translations a
INNER JOIN (SELECT UserID FROM translations WHERE IsFinal = 1) b
ON a.UserID = b.UserID
WHERE IsFinal = 0;
TRY ( not tested )
SELECT t1.* FROM table t1
INNER JOIN table t2 USING(indexID)
WHERE t1.IsFinal <>1
GROUP BY t1.UserID