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`;
Related
I have two tables, if data exist in 1st table then populate flag column with 'Y' if does not populate with 'N', I am comparing only 3 columns, one is number, 2nd is name and 3rd column is datetime. However my busines rule case statment always returns 'Y"
Table 1 (staging table, type1)
column1: number, data (123, 456,756)
column2: name, date('Mike', 'Dray','John')
column3: datetime. data('2018-12-03 14:00:52.000','2018-12-03 14:00:52.000','2018-12-03 14:00:52.000')
Table2 (landing table, type2)
column1 number, data (123, 456,756, 890)
column2: name, date('Mike', 'Dray','John','Chris')
column3: datetime. data('2018-12-03 14:00:52.000','2018-12-03 14:00:52.000','2018-12-03 14:00:52.000','2018-09-20 10:31:39.000')
column4: flagcolumn, data('Y','Y','Y','N')
so last column 4 in table 2 should populate to y/n based if data is in table 1 or not.
I have wrote query as like:
WITH CDE AS (
SELECT T1.number,T1.name,T1.Bdatetime,
FROM dbo.db.table T1)
,CDE1 AS (
SELECT CDE.*,BUS_RULE_valid = (
select case
when EXISTS (
SELECT number, name, datetime
FROM dbo.db.table T1
WHERE number IN
(SELECT number
FROM dbo.db.table2)
AND name
(SELECT name FROM dbo.db.t2)
AND datetime IN
(SELECT datetime FROM dbo.db.t2))
THEN 'Y'
ELSE 'N'
END)
FROM CDE
)
SELECT * FROM CDE1
You're checking if the three values individually exist in the other table, which is likely almost always the case. Looks like you need to check for the combined value, which would look something like the query below.
I took the libery of removing the with part, since that didn't seem necessary here. But you could keep it as well, the solutions would be the same (apart from the table alias used).
SELECT
T1.number_col,
T1.name_col,
T1.datetime_col,
CASE WHEN EXISTS (
SELECT 'x' FROM dbo.db.table2 T2
WHERE
t2.number_col = T1.number_col AND
t2.name_col = T1.name_col AND
t2.datetime_col = T1.datetime_col)
THEN 'Y'
ELSE 'N'
END AS BUS_RULE_valid
FROM dbo.db.table1 T1
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
)
I have done my research but can not figure out how to do this. It is super simple to insert from another table but I want to include WHERE statements.
I want to insert value of a single column, column_Q from table A into table B's column_Q WHERE table A's column_W = '100' and column_Q does not already exist in table B.
I tried:
INSERT INTO B (column_Q) select DISTINCT(column_Q)
from A WHERE column_W = 100 AND b.column_Q<>a.column_Q;
Where am I doing wrong?
PS. Both tables already contain values. No field is Null.
INSERT
INTO b (q)
SELECT DISTINCT q
FROM a
WHERE a.w = 100
AND a.q NOT IN
(
SELECT q
FROM b
)
If your b.q has a UNIQUE constraint defined on it, then just use:
INSERT
IGNORE
INTO b (q)
SELECT q
FROM a
WHERE w = 100
You cannot refer to the left side of the "assignment", because there is no current row from B to compare to (that would be the one you are inserting) You need to check if a similar row is already present in B, like in:
INSERT INTO B (column_Q)
SELECT DISTINCT(A.column_Q)
FROM A
WHERE A.column_W = 100
AND NOT EXISTS (
SELECT *
FROM B
WHERE B.column_Q = A.column_Q
);
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.
I have a table with a composite key composed of 2 columns, say Name and ID. I have some service that gets me the keys (name, id combination) of the rows to keep, the rest i need to delete. If it was with only 1 row , I could use
delete from table_name where name not in (list_of_valid_names)
but how do I make the query so that I can say something like
name not in (valid_names) and id not in(valid_ids)
// this wont work since they separately dont identity a unique record or will it?
Use mysql's special "multiple value" in syntax:
delete from table_name
where (name, id) not in (select name, id from some_table where some_condition);
If your list is a literal list, you can still use this approach:
delete from table_name
where (name, id) not in (select 'john', 1 union select 'sally', 2);
Actually, no I retract my comment about needing special juice or being stuck with (AND OR'ing all your options).
Since you have a list of values of what you want to retain, dump that into a temporary table. Then do a delete against the base table for what does not exist in the temporary table (left outer join). I suck at mysql syntax or I'd cobble together your query. Psuedocode is approximate
DELETE
B
FROM
BASE B
LEFT OUTER JOIN
#RETAIN R
ON R.key1 = B.key1
AND R.key2 = B.key
WHERE
R.key1 IS NULL
The NOT EXISTS version:
DELETE
b
FROM
BaseTable b
WHERE
NOT EXISTS
( SELECT
*
FROM
RetainTable r
WHERE
(r.key1, r.key2) = (b.key1, b.key2)
)