SQL - Comparing two tables with Minus - Include/Exclude temp field - sql

After carefully reading a lot of topics about comparing tables and using the minus function I'm posting this.
I've got my comparison between two tables running.
Select Column1,Column2.. from table 1
minus Column1,Column2.. from table 2
union all
Column1,Column2.. from table 2
Select Column1,Column2.. from table 1
order by column1
Now this gives me a list of duplicate or single values that are different in each table. This is fine. However I do not have an indicator telling me in which table the (faulty) rows are.
I tried adding a temporary column giving it an A and B field. This results in a full export of the table because this obviously gets taken in with the minus function.
Is there a way that I can tag the rows telling me what table they are in without adding a permanent column in the table,because this is not an option.
Help is much appreciated!

I would phrase this as a union of left joins:
SELECT t1.col1, t1.col2, 'table1' AS label
FROM table1 t1
LEFT JOIN table2 t2
ON t1.col1 = t2.col1 AND t1.col2 = t2.col2
WHERE t2.col1 IS NULL
UNION ALL
SELECT t2.col1, t2.col2, 'table2'
FROM table2 t2
LEFT JOIN table1 t1
ON t1.col1 = t2.col1 AND t1.col2 = t2.col2
WHERE t1.col1 IS NULL
The label column is computed during the UNION and serves to label the origin table for each record (i.e. set of values) which are unique to that particular table. Note that you can extend what I have given above by adding the necessary number of columns to fill both tables.
This is a general solution which should work across most RDBMS, and doesn't rely on any set difference operators.
Demo here:
SQLFiddle

The example query you provided isn't syntactically correct and has errors when running. But, based on the description of what you tried, I think I understand what you're trying to accomplish.
You were on the right track with adding a temporary column that provides an indicator of which table is the source of the row. The value of the temporary column should be the same for the queries before the UNION ALL and a different value for the queries after.
Here's an updated version of your example query. You can try it out at SqlFiddle
(
SELECT 'FromTable1', COLUMN1, COLUMN2, COLUMN3 FROM TABLE1
EXCEPT
SELECT 'FromTable1', COLUMN1, COLUMN2, COLUMN3 FROM TABLE2
)
UNION ALL
(
SELECT 'FromTable2', COLUMN1, COLUMN2, COLUMN3 FROM TABLE2
EXCEPT
SELECT 'FromTable2', COLUMN1, COLUMN2, COLUMN3 FROM TABLE1
)

Related

sql oracle using update

I need to take data from one table to add to another table.
I got two SQL's:
SQL1:
select * from table1;
SQL2:
select * from table2 where coloumn1 = table1.coloumn6 (number)
table1 looks like:
For better understanding we call each coloumn coloumn1, coloumn2, ... coloumn9
table2 looks like:
For better understanding we call each coloumn coloumn1, coloumn2, ... coloumn13
What should happen in text
My SQL has to take the value from table1.coloumn6 (number) - checking if this value is given in table2.coloumn1
select * from table2 where coloumn1 = table1.coloumn6 (SQL2)
If yes it should update the data from table1.coloumn2 (varchar2) to table2.coloumn4 (varchar2).
If I understand correctly, you want to update table1.column2 to the corresponding value in table2.column1 based on other conditions. Based on your description:
update table1
column2 = (select column4 from table2 t2 where t2.column1 = table1.column6)
where exists (select 1 from table2 t2 where t2.column1 = table1.column6);
MERGE is good for updating/inserting tables based on other tables. Something like this should work (would be a bit more clear with distinctly-named columns). It also accepts an optional 'WHEN NOT MATCHED THEN' clause which lets you insert new records.
MERGE INTO table2
USING (SELECT column2, column6 FROM table1) table1
ON (table2.column1 = table1.column6)
WHEN MATCHED THEN
update set column4 = column2;

using sql create a new table with 2 fields, field1 from tableA and field1 from table B

Am new to SQL and am stuck here with a very simple-looking query request.
I have 2 tables, both having exactly the same structure (IE same no. of columns, same no. Of rows) except for the actual contents. so for example,tableA has 2 columns called col1&col2; tableB has 2 columns too called col1&col2. Now I want to create a 3rd new tale, where 1st column is tableA's col1, and 2nd column is tableB's col1. preferably the name of the 1st column is fromTableA, and name of 2nd column is fromTableC. How do I achieve this please? I tried all the following ways but I always get the same error: "number of query values and destination fields are not the same."
variation 1:
insert into newTable(fromTable1,fromTable2)
select col1 from table1
select col1 from table2
variation 2:
insert into newTable(fromTable1,fromTable2)
select col1 from table1,col1 from table2
variation 3:
insert into newTable(fromTable1,fromTable2)
select col1 from table1, table2
Presumably you have fields in the two tables that can be joined, so this:
insert into newtable (romTable1,fromTable2)
select a.col1, b.col1
from table1 a, table2 b
where a.col1 = b.col1;
The a/b are aliases that differentiate between the two columns in each table. If you don't have fields to join then whatever you're trying to do probably needs a rethink.
You may try following sql query to achieve your purpose:
with OrderedTableA as (
select row_number() over (order by Col1) RowNum, *
from TableA (nolock)
),
OrderedTableB as (
select row_number() over (order by Col1) RowNum, *
from TableB (nolock)
)
select T1.Col1, T2.Col2 into TableC
from OrderedTableA T1
full outer join OrderedTableB T2 on T1.RowNum = T2.RowNum
Above query will create a new table as TableC with column col1 from TableA and col2 from TableB. You may change the queries to your need.
I hope you will understand the above queries. Give it a try.

SQL table with a field that contains null values

A table called table1 has a field called field1 with null values in it. This query does not return any rows:
SELECT *
FROM table1
WHERE field1 NOT IN
(
SELECT field1
FROM table1
)
I know there are better ways of writing this query. What causes this behaviour i.e. using not in with a field that contains null values.
OK, I might be missing the point here, but one way to rephrase your query is:
Step 1: Take all values of table1.field1.
Step 2: Return all table1 rows whose field1's value isn't among the values obtained in Step 1.
Surely this always returns the empty set?
In assumption that there is primary key field exists in table, you may use this script:
select
t1.*
from
dbo.Table1 as t1
where
t1.field1 = 'Value1'
and not exists( select 1 from Table1 as t2 where t1.ID != t2.ID and t2.field1 = 'Value2')

Column ambiguously defined in subquery using rownums

I have to execute a SQL made from some users and show its results. An example SQL could be this:
SELECT t1.*, t2.* FROM table1 t1, table2 t2, where table1.id = table2.id
This SQL works fine as it is, but I need to manually add pagination and show the rownum, so the SQL ends up like this.
SELECT z.*
FROM(
SELECT y.*, ROWNUM rn
FROM (
SELECT t1.*, t2.* FROM table1 t1, table2 t2, where table1.id = table2.id
) y
WHERE ROWNUM <= 50) z
WHERE rn > 0
This throws an exception: "ORA-00918: column ambiguously defined" because both Table1 and Table2 contains a field with the same name ("id").
What could be the best way to avoid this?
Regards.
UPDATE
In the end, we had to go for the ugly way and parse each SQL coming before executing them. Basically, we resolved asterisks to discover what fields we needed to add, and alias every field with an unique id. This introduced a performance penalty but our client understood it was the only option given the requirements.
I will mark Lex answer as it´s the solution we ended up working on.
I think you have to specify aliasses for (at least one of) table1.id and table2.id. And possibly for any other corresponding columnnames as well.
So instead of SELECT t1.*, t2.* FROM table1 t1, table2 use something like:
SELECT t1.id t1id, t2.id t2id [rest of columns] FROM table1 t1, table2 t2
I'm not familiar with Oracle syntax, but I think you'll get the idea.
I was searching for an answer to something similar. I was referencing an aliased sub-query that had a couple of NULL columns. I had to alias the NULL columns because I had more than one;
select a.*, t2.column, t2.column, t2.column
(select t1.column, t1.column, NULL, NULL, t1.column from t1
where t1='VALUE') a
left outer join t2 on t2.column=t1.column;
Once i aliased the NULL columns in the sub-query it worked fine.
If you could modify the query syntactically (or get the users to do so) to use explicit JOIN syntax with the USING clause, this would automatically fix the problem at hand:
SELECT t1.*, t2.*
FROM table1 t1
JOIN table2 t2 USING (id)
The USING clause does the same as ON t1.id = t2.id (or the implicit JOIN you have in the question), except that only one id column remains in the result, thereby eliminating your problem.
You would still run into problems if there are more columns with identical names that are not included in the USING clause. Aliases as described by #Lex are indispensable then.
Use replace null values function to fix this.
SELECT z.*
FROM(
SELECT y.*, ROWNUM rn
FROM (
SELECT t1.*, t2.* FROM table1 t1, table2 t2, where
NVL(table1.id,0) = NVL(table2.id,0)
) y
WHERE ROWNUM <= 50) z
WHERE rn > 0

Insert a Row with values from multiple tables (SQL Server)

I'm defining a delete trigger, and I need to backup the row deleted but only a few arguments from the original and including one column from other table:
TableC:
* Column 1: value from a column in TableA
* Column 2 to 6: values from colums 1,2,3,5,6 from TableB
All I want is something like this:
INSERT into TableC values (
(SELECT Column1A from TableA where TableA.Column = 'SomeValue'),
(SELECT column1, column2, column3, column5, column6 from TableB));
The result on TableC must be:
Column1A , column1, column2, column3, column5, column6
But that is not working.
In my special case, TableB is the deleted table accessible only in triggers.
I'm using SQL-Server 2008 but all I need is the logic of the query, and then I try to translate it.
Thank you.
In another case, which I honestly find very odd, that might be closer to what you're describing, this might work:
INSERT INTO MyTable
SELECT
(SELECT ColumnA FROM Table1),
Table2.ColumnA,
Table2.ColumnB,
Table2.ColumnC,
Table2.ColumnD
FROM
Table2
That way, you're only selecting that one column from Table1, yet selecting many columns from Table2, regardless of any relationship between them.
You need to do joins on the select.
Here's an example:
INSERT INTO MyTable
SELECT
Table1.ColumnA,
Table1.ColumnB,
Table2.ColumnA,
Table2.ColumnB
FROM
Table1
INNER JOIN Table2 ON Table1.ID = Table2.ID
This is just an example of "inserting from two tables".
You need to modify it to match what you're looking for, which I did not comprehend from your arbitrary example.
You can use a cross join to join unrelated tables:
INSERT MyTable
(col5, col7)
SELECT t1.col5
, t2.col7
FROM Table1 t1
CROSS JOIN
Table2 t2
WHERE t1.ID = 'SomeValue'
and t2.ID = 'OtherValue'
If one of the tables just contains one row, you can omit the where part for it.