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?
Related
I have two tables Table1 and Table2
In Table 1 column mobile has multiple entries of Mobile number.
I want to get the id of those repeating mobile number from table1 and search that ids of table1 in table2 where clientId = table1.id.
I tried the below SQL code for obtaining id of repeating mobile number
SELECT id FROM table1 GROUP BY mobile HAVING COUNT(*) > 1
then I tried feeding the values into a new array where table1.id = table2.clientId
foreach ($table1data as $key) {
$items[] = \Yii::$app->db->createCommand("
SELECT clientId
FROM table2
WHERE clientId = :cid
")
->bindValue(':cid',$key['id'])
->queryAll();
}
If table1 (id) has identical value then you can use INNER JOIN with EXISTS :
select t2.*
from table2 t2 inner join
table1 t1
on t1.id = t2.clientId
where not exists (select 1 from table1 t11 where t11.mobile = t1.mobile and t11.id <> t.id);
as we know - "INNER JOIN with complex condition dramatically increases the execution time please refer this"
consider the query
(
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P1 = Table2.P1 OR Table1.P2 = Table2.P2
)
Over here comparison will be done via "nested loops" so execution time will be more but if we have a query like-
(
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P3 = Table2.P3 where Table1.P1 = "abc" OR
Table2.p2 = "xyz"
)
or like-
(
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P3 = Table2.P3 where Table1.P1 LIKE "abc" OR
Table2.p2 LIKE "xyz"
)
than also does the comparison will take place through nested loops only (for columns P1 ANd P2)?
Please Use Union instead of 'OR' condition in JOIN.
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P1 = Table2.P1
UNION All
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P2 = Table2.P2 AND Table1.P1 <> Table2.P1
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;
I'm trying to inner join table1 <- to -> table2, table3, table4 OR table5 depending on a field present in table1. So, if the field information in table1 has the value example_get_from_two I should inner join table1 with table2 as to obtain a given row, if in another row table1 has the value example_get_from_three I should inner join table1 with table3 and so on. This is the query I tried, but it returned zero rows:
SELECT n.notification_type,
(CASE WHEN n.notification_type = 'two' AND n.information = t2.somefield
THEN t2.anotherfield
WHEN n.notification_type = 'three'
THEN (CASE WHEN t3.field = '1' THEN t3.otherfield ELSE t3.yetanotherfield END)
WHEN n.notification_type = 'four' AND t4.field = n.information
THEN t4.anotherfield
WHEN n.notification_type = 'five'
THEN t5.field
END) AS information FROM table0 zero, notifications n
INNER JOIN table1 t1 ON(n.information=t1.somefield AND n.notification_type = 'something')
INNER JOIN table2 t2 ON(n.information=t2.somefield AND n.notification_type = 'something')
INNER JOIN table3 t3 ON((n.information=t3.somefield OR n.information=t3.someotherfield) AND n.notification_type = 'something')
WHERE zero.field ='something' AND n.id = zero.id
Unfortunately this retrieves zero rows and shouldn't , probably because all joins are made despite the actual value of information, and n.notification_type = "something". Is this possible with cases or similar? What I'd like to obtain is
fromfield1 | fromfield2 | fromfield3 (this one is "dynamic" and
depends on the joined table)
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