I have 2 tables 'conta' and 'details' and both the tables have null values and data in different case
conta
id col1 col2 col3 col4
1 Hi Bye See YOU
2 Hello (NULL) (NULL) (NULL)
details
id new_column1 new_column2 new_column3
1 bye see you
I want to apply join based on col2=new_column1 and col3 = new_column2 and col4 = new_column3 and get the values that are present in conta and not in details, so my output will be
conta
id col1 col2 col3 col4
2 hello (NULL) (NULL) (NULL)
But somehow i am unable to do so. I wrote below query, but its simply not resulting me the values i want.
SELECT `id`,`col1`,`col2`,`col3`,`col4` FROM `conta`
WHERE LOWER(`col2`) + LOWER(`col3`) + LOWER(`col4`) NOT IN (SELECT DISTINCT(LOWER(`new_column1`) + LOWER(`new_column2`) + LOWER(`new_column3`))
FROM `details`);
It simply give me no results! in the display
Any help?
Edit: I tried below query as suggested by #Uueerdo and it isn't giving me what i want.
SELECT conta.id,`col1`,`col2`,`col3`,`col4` FROM `conta`
LEFT OUTER JOIN `details`
ON ((conta.col2 IS NULL AND details.new_column1 IS NULL)
OR (LOWER(conta.col2) = LOWER(details.new_column1)))
AND ((conta.col3 IS NULL AND details.new_column2 IS NULL)
OR (LOWER(conta.col3) = LOWER(details.new_column2)))
AND ((conta.col4 IS NULL AND details.new_column3 IS NULL)
OR (LOWER(conta.col4) = LOWER(details.new_column3)))
WHERE details.id IS NULL
In the output in col2 i see a value 'Operations' which is also present in new_column1 in details table. This means it shouldn't be present in the output as i am trying to apply left outer join exclude I even tried using LEFT JOIN instead of LEFT OUTER JOIN and it isn't working either
Edit2: I found the solution. the query works and does the job. Exept that i had to run a command to replace all blank cells in the columns where i am applying join to NULL values.
You're better off using a SELECT .... FROM a LEFT JOIN b ON conditions WHERE b.id IS NULL style of query; null comparisons are a little different (and can be handled join conditions).
For example these evaluate to NULL, which is not true, which is false:
NULL = NULL
NULL IN (NULL)
But you can do things like this to compare nulls more easily:
ISNULL(a, x) = ISNULL(b, x)
(a IS NULL AND b IS NULL)
So you're join condition can be something like:
[...]
ON ((conta.col2 IS NULL AND details.new_column1 IS NULL)
OR (LOWER(conta.col2) = LOWER(details.new_column1)))
AND ((conta.col3 IS NULL AND details.new_column2 IS NULL)
OR (LOWER(conta.col3) = LOWER(details.new_column2)))
[and so on...]
WHERE details.id IS NULL
This assumes details has some sort of non-null row identification field that can used to reliably determine if there was a match or not.
Edit: The precise problem with your current query (aside from the null issues I previously outlined) is that + is not concatenation in MySQL, it is addition. With the data you've shown both LOWER(col2) + LOWER(col3) + LOWER(col4) and LOWER(new_column1) + LOWER(new_column2) + LOWER(new_column3) with yield 0 for the rows without NULL values in them. You would need to use the CONCAT() function to do the operation instead; but I'd discourage it because CONCAT('abc', 'def', '') is equal to CONCAT('ab', 'cd', 'ef').
Sidenote: DISTINCT is not a function, the () will have no effect (other than that they would cause a problem if they contained more than one result field).
You can keep your general format, and the aforementioned null issues, by a simple change with this format : WHERE (a, b, c) IN (SELECT a, b, c FROM ....
You can do a left join, then test for a null in the 2nd table to find the rows in the first table that didn't match any rows in the 2nd table.
SELECT
a.`id`,
a.`col1`,
a.`col2`,
a.`col3`,
a.`col4`
FROM `conta` a
LEFT JOIN `details` b
ON a.`col2` like b.`new_column1`
AND a.`col3` like b.`new_column2`
AND a.`col4` like b.`new_column3`
WHERE b.`id` IS NULL
Your Problem Solution Is inner join your (contact table) with (details table)
and get (contact.*) All columns where Contact.col1 !=details.new_column1
here is a query
Select conta.* from conta inner join details on conta.col1!=details.new_column1
You Can And More Where column in inner join
You could use the EXISTS operator to create an anti-semi join. Please take a look at this link: https://www.techonthenet.com/mysql/exists.php
Example Query:
SELECT
id,
col1,
col2,
col3,
col4
FROM conta
WHERE NOT EXISTS (
SELECT 1
FROM details
WHERE conta.col2 LIKE details.new_column1
AND conta.col3 LIKE details.new_column2
AND conta.col4 LIKE details.new_column3
)
Related
Is there any way we can do this in SQL?
Les say I have table Tablename_1 as below:
id
col1
1
data1
2
data2
3
data3
4
data4
5
data5
I want to check if the data I have in my where clause is present in the table or not
for example, where clause is as:
where id in (1,3,5,7);
Then I wish to output as below:
id
data_result
1
YES
3
YES
5
YES
7
NO
There are a few ways to do this.
One option is to provide your IDs as a table-valued constructor (VALUES() clause) instead of a WHERE clause. Then you can LEFT JOIN from this new "table" to create your result.
This is the MySql version (Postgresql needs to remove the row keywords):
select a.n, case when t1.id IS NULL then 'N' else 'Y' end as data_result
from (values row(1), row(3),row(5),row(7)) as a(n)
left join tablename_1 t1 on a.n = t1.id
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=028e5a984e5ed2969247e025bc8776be
You can also do this in a CTE via UNION:
WITH base as (
SELECT 1 as n UNION SELECT 3 UNION SELECT 5 UNION SELECT 7
)
SELECT base.n, case when t1.id IS NULL then 'N' else 'Y' end as data_result
FROM base
LEFT JOIN tablename_1 t1 on base.n = t1.id
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ef2a88f6f89bf4101d7d651b4440ac28
This works the same in both databases, but as you can see means building a up lot more code per value in your list.
A final option is creating a dynamic numbers table. Then you can again LEFT JOIN these tables together to find out the Yes/No result for all possible values in the dynamic table and then still put your desired values in a WHERE clause to only show those results. The trick here is it requires you to have some idea of the possible scope for your values up front, and can make things a little slower if your guess is too far off.
Any of these could also be written to use an EXISTS() clause, which can often perform better. I just find the JOIN easier to write and reason about.
You could also use exists with the values approach from Joel
Something like
select v.*,
case when exists(select 1 from Tablename_1 as t where t.id=v.id) then
'Yes'
else
'No'
end
from (values (1),(3),(5),(7)) as v(id)
You can use ANY.
select Tablename_1.id,
case
when Tablename_1.id = ANY (ARRAY[1, 3,5,7])
then 'YES'
else 'NO' end
as data_result
from Tablename_1;
further reading: IN vs ANY operator in PostgreSQL
I am trying to update a value to be NULL where tracker_unique_id can be found in ab_split_tracker_unique_link where that ones ab_split_id can be found in a 3rd table ab_split_candidate.
I cant do it by giving it different values as they can be different from user to user on locals
UPDATE trustpilot_links SET `invite_after_enquiry` = NULL
WHERE EXISTS (
SELECT tracker_unique_id, ab_split_tracker_unique_link.ab_split_candidate_id
FROM ab_split_tracker_unique_link
WHERE EXISTS (
SELECT ab_split_candidate_id
FROM ab_split_candidate LEFT JOIN ab_split
ON ab_split_candidate.ab_split_id = ab_split.ab_split_id WHERE ab_split.reference="review_invite_after_enquiry"
)
);
Edit:
Table examples
Trustpilot Links
trustpilot_link_id | invite_after_enquiry | tracker_unique_id
1 1 123
2 0 1234
ab_split_tracker_unique_link
tracker_unique_id | ab_split_id
1234 32
Ab Split
ab_split_id | reference
32 review_invite_after_enquiry
I want to set values to null if there tracker cannot be found in table ab_split_tracker_unique_link with an ab_split_id that is equal to review_invite_after_enquiry in ab_split
Your subqueries are not related to their parent queries as they should be. Let's look at your inner-most query:
SELECT ab_split_candidate_id
FROM ab_split_candidate
LEFT JOIN ab_split ON ab_split_candidate.ab_split_id = ab_split.ab_split_id
WHERE ab_split.reference = 'review_invite_after_enquiry'
Well, first of all your WHERE clause dismisses outer-joined records, so this is essentially an INNER JOIN. But then: either there are such records or not. This has nothing to do with the record your are potentially updating, nor with the ab_split_tracker_unique_link you are looking up.
So either you are updating all records or none.
We would rather expect something like
UPDATE trustpilot_links tl
SET invite_after_enquiry = NULL
WHERE EXISTS
(
SELECT *
FROM ab_split_tracker_unique_link stul
WHERE stul.tracker_unique_id = tl.tracker_unique_id
AND ...
);
So add WHERE clauses that relate the subqueries to their parent queries.
I am trying to split a table into two referenced tables and am having issues with the population of one of the new tables. Say the old table has columns A, B, C, X, Y, Z and the first new table to have A, B, C, ID and the second to be ID, X, Y, Z.
Populating the second table is trivial:
INSERT INTO newTable2 (`X`,`Y`,`Z`)
SELECT DISTINCT `X`,`Y`,`Z`
FROM oldTable;
I can check newTable2 after this has been run and see that is populated properly. ID is populated by the table definition and there are no null values. I seem to have issues with populating the first table. I attempted to use this script:
INSERT INTO newTable1
SELECT oldTable.`A`
, oldTable.`B`
, oldTable.`C`
, newTable2.`ID`
FROM oldTable
LEFT JOIN newTable2
ON newTable2.`X` = oldTable.`X`
AND newTable2.`Y` = oldTable.`Y`
AND newTable2.`Z` = oldTable.`Z`;
But when I check the resulting table I get null values for ID for most rows. Due to how it's populated newTable2 should have a row and ID for every row of oldTable and every row with a null that I have checked manually has had a value that was simply not found.
I am running MySql 5.7 and all columns except ID are of the type varchar.
Your JOIN condition does not handle NULL values. You have to handle them if you want to get all your original values back.
Use something like this for each columns which can contain NULL values.
(newTable2.`X` = oldTable.`X` OR (newTable2.`X` IS NULL AND oldTable.`X` IS NULL))
As #Pred mentioned you should handle the NULL case in your Join statements. I would use the null-safe <=> operator to avoid the OR statement:
Something like the following:
INSERT INTO newTable1
SELECT oldTable.`A`
, oldTable.`B`
, oldTable.`C`
, newTable2.`ID`
FROM oldTable
LEFT JOIN newTable2
ON newTable2.`X` <=> oldTable.`X`
AND newTable2.`Y` <=> oldTable.`Y`
AND newTable2.`Z` <=> oldTable.`Z`;
In mysql I have tableA with rows userid and valueA and tableB with userid and valueB.
Now I want all entries from tableA which don't have an entry in tableB with the same userid.
I tried several things but can't figure out what I do wrong.
SELECT * FROM `tableA`
left join `tableB` on `tableA`.`userid` = `tableB`.`userid`
This is a very good start actually. It gives me all entries from tableA + the corresponding values from tableB. If they don't exist they are displayed as NULL (in phpmyadmin).
SELECT * FROM `tableA`
left join `tableB` on `tableA`.`userid` = `tableB`.`userid`
where `tableB`.`valueB` = NULL
Too bad, empty result. Maybe this would have been too easy. (By the way: tableA has ~10k entries and tableB has ~7k entries with userid being unique in each. No way the result would be empty if it would do what I want it to do)
SELECT * FROM `tableA`
left join `tableB` on `tableA`.`userid` = `tableB`.`userid`
where `tableA`.`userid` != `tableB`.`userid`
This doesn't work either, and to be honest it also looks totally paradox. Anyways, I'm clueless now. Why didn't my 2nd query work and what is a correct solution?
You are almost there. That second query is SO close! All it needs is one little tweak:
Instead of "= NULL" you need an "IS NULL" in the predicate.
SELECT * FROM `tableA`
left join `tableB` on `tableA`.`userid` = `tableB`.`userid`
where `tableB`.`valueB` IS NULL
^^
Note that the equality comparison operator = will return NULL (rather than TRUE or FALSE) when one side (or both sides) of the comparison are NULL. (In terms of relational databases and SQL, boolean logic has three values, rather than two: TRUE, FALSE and NULL.)
BTW... the pattern in your query, the outer join with the test for the NULL on the outer joined table) is commonly referred to as an "anti-join" pattern. The usual pattern is to test the same column (or columns) that were referred to in the JOIN condition, or a column that has a NOT NULL constraint, to avoid ambiguous results. (for example, what if 'ValueB' can have a NULL value, and we did match a row. Nothing wrong with that at all, it just depends on whether you want that row returned or not.)
If you are looking for rows in tableA that do NOT have a matching row in tableB, we'd generally do this:
SELECT * FROM `tableA`
left join `tableB` on `tableA`.`userid` = `tableB`.`userid`
where `tableB`.`userid` IS NULL
^^^^^^ ^^
Note that the IS NULL test is on the userid column, which is guaranteed to be "not null" if a matching rows was found. (If the column had been NULL, the row would not have satisfied the equality test in the JOIN predicate.
Change = NULL for IS NULL on your code. You can also use NOT EXISTS instead:
SELECT *
FROM `tableA` A
WHERE NOT EXISTS (SELECT 1 FROM `tableB`
WHERE `userid` = A.`userid`)
this will help explain the use of working with NULL values:
http://dev.mysql.com/doc/refman/5.0/en/working-with-null.html
the less expensive query would be this, all the other queries sugested are too expensive if the database is too big:
SELECT * FROM tableA a
WHERE a.userid NOT IN
(SELECT b.user_id FROM tableB b);
Ive seen plenty of examples but none seem to get me where I need it.
I want to Select 1 field from table A, then Check table B for a value, if that value is true(boolean) then also Select field 2 and 3 from table A to return all 3 fields. So if value from B is false only 1 field is selected from table A, if true, all 3 are selected.
Select Field1
, Case
When Exists (
Select 1
From TableB
Where SomeField = 1
And ...
) Then TableA.Field2
Else Null
End As Field2
, Case
When Exists (
Select 1
From TableB
Where SomeField = 1
And ...
) Then TableA.Field3
Else Null
End As Field3
From TableA
Update
The above solution works fine if what you want is a three column result every time even if some of those columns are null. However, if what you want is a different number of columns returned based on the query, then this is something that cannot be done in a single query. The SQL language was not geared to handle on-the-fly schema generation. My suggestion would first be to evaluate why you want a different number of columns from the same query and determine if you cannot simply handle the scenario in your middle-tier where column 2 or 3 is NULL. That is by far the simplest solution and could be done in a single query:
Select TableA.Field1, TableA.Field2, TableA.Field3
, (
Select TableB.SomeBooleanColumn
From TableB
) As TableBValue
From TableA
Your middle-tier code would then determine whether to do something with Field2 and Field3.
That said, if you insist on having two column structures, you need two queries:
Select TableA.Field1
From TableA
Where Exists (
Select 1
From TableB
Where TableB.SomeColumn = 0
)
After calling this query, you would evaluate whether you got a row. If you got no rows, you could then call this query:
Select TableA.Field1, TableA.Field2, TableA.Field3
From TableA
Where Exists (
Select 1
From TableB
Where TableB.SomeColumn = 1
)
What hasn't be stated in the OP is the scenario where there is no row in TableB.
Use case expressions:
select A.field1,
case B.boolValue when 1 then A.field2 end AS field2,
case B.boolValue when 1 then A.field3 end AS field3
from TableA A join TableB B on A.? = B.?
I don't know what your A and B tables are linked on so you'll have to fill in the ? marks. This will return null values for field2 and field3 when B.boolValue is false.