I have 2 tables 'A' and 'B'. Both have a common column 'name' and linked with each other by a column 'id'. The column 'name' in the table A is empty whereas it has data in table B. My task is to fill all the data in that column from table B to table A with corresponding ids.
I'm using the following query:
UPDATE A
SET A.name = (SELECT B.name from B WHERE A.id = B.id)
WHERE EXISTS
(SELECT B.name from B)
As soon as I run the query in SQL developer, it just freezes and i have to force close it. Can anyone tell me what's wrong with the query?
Try this one instead:
UPDATE A
SET A.name = (SELECT B.name FROM B WHERE B.id = A.id AND B.name IS NOT NULL)
WHERE a.name IS NULL;
Since you're using Oracle, here's the reference for IS NOT NULL.
Here's the SQL Fiddle so that you can play with it: http://sqlfiddle.com/#!4/a5ad0/3
I'm not sure from the above conversation whether you made any changes beyond indexing your data, but you should include a WHERE EXISTS clause as mentioned. The complete query should look like this:
UPDATE A
SET A.name = ( SELECT B.name FROM B WHERE B.id = A.id )
WHERE EXISTS ( SELECT 1 FROM B WHERE B.id = A.id )
The WHERE EXISTS clause in your original query won't do much of anything except check to see if there is at least one non-NULL value of name in B.
Related
I have two tables, table A and table B. Table A has a list of item names, and their unique IDs. Table B has a list of those same item names, but not the IDs. I want to copy the IDs over to table B based on the item name. I've already created the column in a separate command in table B, but I'm having trouble figuring out how to copy this over. I used the following code:
Update B
Set B.ID =
(Select A.ID From A Where A.Name = B.Name)
Where Exists (Select A.ID From A Where A.Name = B.Name);
But I keep getting errors with it. Specifically:
SQL Error: ORA-01427: single-row subquery returns more than one row
01427. 00000 - "single-row subquery returns more than one row"
ID is Alphanumeric. Names and IDs are not necessarily unique, so if a name value recurs I want it to still assign the correct ID.
Help?
You have to define what the "correct" id is. You can easily get one id, using either rownum or an aggregation function:
Update B
Set B.ID = (Select A.ID From A Where A.Name = B.Name and rownum = 1)
Where Exists (Select A.ID From A Where A.Name = B.Name);
or:
Update B
Set B.ID = (Select max(A.ID) From A Where A.Name = B.Name)
Where Exists (Select A.ID From A Where A.Name = B.Name);
One of these should address your problem.
Although I would not recommend it, you could also get a list of all matching ids:
Update B
Set B.ID = (Select listagg(A.ID, ',') within group (order by A.ID) From A Where A.Name = B.Name)
Where Exists (Select A.ID From A Where A.Name = B.Name);
I do abhor storing lists as comma-delimited strings, however.
Another way is to use for loop, see below code.
BEGIN
FOR tab_a IN (SELECT ID, NAME
FROM table_a)
LOOP
UPDATE table_b
SET id = tab_a.id
WHERE name = tab_a.name;
--comment dbms_output if a lot of records involved or you can increase the output size
DBMS_OUTPUT.PUT_LINE(tab_a.name||':::'||SQL%ROWCOUNT);
END LOOP;
END;
/
COMMIT;
I have some Problem, there are two Tables, they communicate with the value ID.
Now I will set the value from Column a in Table A with the value 'Nein', but only if the value of the column b in Table B is '0' and
if a.id = b.id.
How can I do that?
Thanks
You'll need to make a Join in the Update Statement like:
UPDATE a set ColumnA='Nein' from TableA a inner join TableB b on a.id=b.id WHERE b.ColumnB='0'
please try the below query . Since there here i am not sure that id is primary column in table , i have used "in" clause .
update A
set A.a ='Nein'
where A.id in ( select A.id from A ,B
where A.id = B.id and B.b='0')
Try with
update A a set a.a='Nein'
where a.id in (select b.id from B b where B.b='0' and a.id=b.id);
In SQL, I am joining a table onto itself:
SELECT * FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
So it's fetching all the rows which have the same NAME appearing in a row of the other table (will also return the same row twice!).
Let's say that I want to save the result into a temporary table, say something like:
SELECT * INTO ##temp_table FROM (
SELECT * FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
Oh dear. SQL says:
The column 'NAME' was specified multiple times.
Reason: SQL can only create a table if every column name is unique.
Obvious solution: give every column name in the "second table" an alias.
My problem is that the actual tables I'm working with have about 40 columns. Giving every one of those columns an alias seems like a wasteful use of time. Sure, I don't need every column so could drop some of them, but deciding which ones I require just now also seems wasteful.
Question: is there a shorthand way to rename every column? For example, can I append every column name with a _2 or an _a?
Ok, you have a query, with 2 joined tables, wich returns both tables columns (i don't care if you are joining the same table with itself).
So you have two possible results
Show both colums, with differents alias (AS)
SELECT * INTO ##temp_table FROM (
SELECT a.Name AS NameA, b.Name AS NameB FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
Or, if you don't want them duplicated (because the other will return two times the same name)
SELECT * INTO ##temp_table FROM (
SELECT a.Name FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
And what if you have more colums? Ok, you can just show one of the tables in the JOIN
SELECT * INTO ##temp_table FROM (
SELECT b.* FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
Sorry for my bad english! I hope this can help you!
I suggest querying sys.tables and sys.columns to get your renamed fields quickly:
SELECT c.name + '_2,' ColumnName
FROM sys.columns c
JOIN sys.tables t
ON c.object_id = t.object_id
WHERE t.name = 'YourTable'
Or you can combine with the OBJECT_ID() function:
SELECT c.name + '_2,' ColumnName
FROM sys.columns c
WHERE object_id = OBJECT_ID('YourTable')
Example query:
Select id, id_dtm
From tableA
Where exists (
Select 1
From tableB b, tableC c, tableD d
Where b.id = id
And b.id_dtm = id_dtm
And b.id = c.id
And c.id = d.id);
The problem with the above query is that all 4 tables have columns named id and id_dtm.
When i run it, i get an error saying that the columns ORA-00918: column ambiguously defined
I could have fixed by using an alias in tableA but the problem is that the query is generated dynamically. The where exists portion is generated somewhere else and the bit before it is merged later so i cant use an alias as it is now.
Is there any way i can use id and id_dtm from tableA inside the where exists clause without using an alias for tableA?
Database is Oracle10G
Write the table name tableA:
Select id, id_dtm
From tableA
Where exists (
Select 1
From tableB b, tableC, tableD
Where tableB.id = tableA.id
And tableB.id_dtm = tableA.id_dtm
And tableB.id = tableC.id
And tableC.id = tableD.id)
I don't know your exact setup but why can't you set an alias on the outer table? It doesn't have to reflect the actual table used, just alias it with "outer" or something. The use that in the inner query, you already know that id exists in whatever table is used outside so outer.id would work fine.
The fields in the subquery which refer to tableA (i.e. id and id_dtm) also exist in the other tables, and so they are ambiguous. Solve this by prefixing those with the alias given to tableA:
Select A.id, A.id_dtm
From tableA A
Where exists (
Select 1
From tableB b, tableC c, tableD d
Where b.id = A.id
And b.id_dtm = A.id_dtm
And b.id = c.id
And c.id = d.id);
I am doing a join between two tables and want to select the columns based on whether they have a record or not. I'm trying to avoid having multiple of the same field and am trying to condense them into single columns. Something like:
Select
id = (CASE WHEN a.id IS NULL THEN b.id ELSE a.id END),
name = (CASE WHEN a.name IS NULL THEN b.name ELSE a.name END)
From Table1 a
Left Join Table2 b
On a.id = b.id
Where a.id = #id
I'd like id to populate from Table1 if a record exists, but if not pull from Table2. The previous code returns no records because there are no NULL values in Table1 so my question is how do I run a check to see if any records even exist? Also if anyone knows of a better way to accomplish what I am trying to do I appreciate guidance and constructive criticism.
EDIT
It looks like COALESCE will work for what I'm trying to accomplish. I'd like to give a little more info on exactly what I am working with and get some advice on whether I am using the best method.
I have a bloated table Table2 and it is in production. I'm working on building new web applications for this system but can't justify a complete database redesign so I am trying to do one "on the fly". I've created a new table Table1 and I am writing stored procedures for the following methods Get(Select), Set(Update), Add(Insert), Remove(Delete). This way, to my code, it will seem that I am working with a single table that is not bloated. My code will simply call one of the SP methods and then the stored procedure will handle the data between the old table and the new. I am currently working on the Get method and I need to check the old table Table2 for a record if it doesn't exist in Table1.
Thanks to the suggestions here my query currently looks like this:
Select
id = coalesce(a.id, b.student_number),
first_name = coalesce(a.first_name, b.first_name),
last_name = coalesce(a.last_name, b.last_name),
//etc
From Table1 a
Full Outer Join Table2 b
On a.id = b.student_number
Where (a.id = #id Or b.student_number = #id)
This works for what I'm trying to accomplish, I'd like to throw it out there to the experienced crowd for any tips or suggestions if there are better or more correct ways to go about this.
Thanks
I suspect your problem may come from doing a left join. Try again using a full outer join, like this:
Select
id = coalesce(a.id, b.id),
name = coalesce(a.name, b.name)
From Table1 a
full outer Join Table2 b
On a.id = b.id
Where a.id = #id
Select id = coalesce(a.id, b.id),
name = coalesce(a.name, b.name)
From Table2 b
Left Join Table1 a On a.id = b.id
Where b.id = #id
You may need to use ISNULL or CASE instead of COALESCE depending on your database platform.
First, you don't need a case statement for that:
Select ISNULL(a.id,b.id) AS id, ISNULL(a.name,b.name) AS name,
From Table1 a
Left Join Table2 b
On a.id = b.id
Where a.id = #id
Second, if I get it right, the id field can contain nulls, and in that case you are screwed. I mean, the ID is a unique value that identify a row, if it can be null, you can't identify that row.
But if what you want is getting records from Table1 and Table2 and avoid duplicates, a simple UNION will work fine, since it discards duplicates:
select id, name
from Table1
where id = #id
union
select id, name
from Table2
where id = #id
You could do something like:
select id, name from Table1 a where a.id not in (select id from Table2)
UNION
select id, name from Table2 b
This would give you all the records from table1 that didn't have a corresponding match in table2 plus all of table2's records. The union would then combine the results.
In your first CASE statement, a.id and b.id will always be same value, except for instances in which a.id has a value and b.id generates a NULL value because of the LEFT JOIN. There will never be a row in the result set with a NULL a.id value and a non-NULL b.id value. You could just use a.id for this column.
For the second CASE statement, you may find the name column in either or both tables with a value (and, of course, the values may be different). You said you want to "condense" the these column values; the SQL function for that is COALESCE:
COALESCE(a.id, b.id)
which returns the first non-NULL value (a.id if it isn't NULL, otherwise b.id). It won't tip you off to different names in the two tables.