Updating Records in Table A based on Records in Table B - sql

I have to write a statement which fills a table (customers) with synthetically generated values. There is an addtional constraint that I should only fill those attributes (columns) with a special property (i.e. formally do a projection on them and then operate on them exclusively). These properties are stored in a second table, attributes.
My first draft consists of the following two statements:
-- Get the attributes (columns) we are interested in only
SELECT attributeID from attributes
WHERE tableID = 'customers'
-- Iterate over each row of customers, filling only those attributes (columns)
-- obtained by the above SELECT statement
UPDATE customers
SET (use the records from above select statement...)
Now my problem is how to put them together. I know there is the possibility of appending a WHERE clause to the SET clause, but that would select rows, not columns, as I need. I also read about PIVOT, but so far only inside one single table, not two, as is the case here. I would be very thankful for any hint, since I have no idea how to do this.

is not it you're looking for?
SQL Update Multiple Fields FROM via a SELECT Statement
UPDATE
Table
SET
Table.col1 = other_table.col1,
Table.col2 = other_table.col2
FROM
Table
INNER JOIN
other_table
ON
Table.id = other_table.id

Standard SQL-92 requires a scalar subquery:
UPDATE customers
SET attributeID = (
SELECT A1.attributeID
FROM attributes AS A1
WHERE A1.tableID = 'customers'
);
However, UPDATE customers...WHERE A1.tableID = 'customers' "smells" like you may be mixing data with metadata.

Related

Inserting from one table or view into another but avoid combination duplicates- Can this be done in SQL? If so how?

I have a table that has a primary key WORKITEMID, and the following 3 foreign keys PRODSERVID,PROCESSID,and TASKKNOWID.
I have a view that I can create that also has PRODSERVID,PROCESSID, AND TASKKNOWID. This view will usually have ALL the records in above table plus some new ones - not in the table. The 'table' by definition is meant to hold the unique combinations of PRODSERVID, PROCESSID, and TASKKNOWID.
I would like to insert from the view into the table any new combinations in the view not present in the table. And I don't want to overwrite the existing WORKITEMIDs in the INSERT- because those WORKITEMIDs are used elsewhere.
Can this be done in SQL?
Thanks
Absolutely, the simplest form of criteria for this is to use the negation of EXISTS()
INSERT INTO [TableName] (PRODSERVID,PROCESSID,TASKKNOWID,... )
SELECT PRODSERVID,PROCESSID,TASKKNOWID,...
FROM [ViewName] v
WHERE NOT EXISTS (
SELECT 1 FROM [TableName] t
WHERE t.PRODSERVID = v.PRODSERVID AND t.PROCESSID = v.PROCESSID AND t.TASKKNOWID = v.TASKKNOWID
)
replace the ... with your other fields
You could also use a non-corellating outer join but I find not exists makes the intent much clearer.
There is a good comparison of the different approaches to this issue in this article: T-SQL commands performance comparison – NOT IN vs SQL NOT EXISTS vs SQL LEFT JOIN vs SQL EXCEPT

Postgres UPDATE..FROM query with multiple updates on the same row

I am attempting to optimise a bulk UPDATE statement in Postgres using the UPDATE..FROM syntax to update from a list of values. It works except when the same row might be updated more than once in the same query.
For example say I have a table "test" with columns "key" and "value".
update test as t set value = v.value from (values
('key1', 'update1'),
('key1', 'update2') )
as v (key, value)
where t.key = v.key;
My desired behavior is for the row with key 'key1' to be updated twice, finishing with value set to 'update2'. In practice sometimes the value is updated to update1 and sometimes to update2. Also an update trigger function on the table is only invoked once.
The documentation (http://www.postgresql.org/docs/9.1/static/sql-update.html) explains why:
When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the from_list, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.
Because of this indeterminacy, referencing other tables only within sub-selects is safer, though often harder to read and slower than using a join.
Is there any way to reformulate this query to achieve the behavior I'm looking for? Does the reference to sub-selects in the documentation give a hint?
Example (assuming id is a PK in the target table, and {id, date_modified} is a PK in the source table)
UPDATE target dst
Set a = src.a , b = src.b
FROM source src
WHERE src.id = dst.id
AND NOT EXISTS (
SELECT *
FROM source nx
WHERE nx.id = src.id
-- use an extra key field AS tie-breaker
AND nx.date_modified > src.date_modified
);
(in fact, this is deduplication of the source table -> forcing the source table to the same PK as the target table)

Sql Column had no values

I have a sql table that I am trying to add a column from another table to. Only when I execute the alter table query it does not pull the values out of the table to match the column where I am trying to make the connection.
For example I have column A from table 1 and column A from table 2, they are supposed to coincide. ColumnATable1 being an identification number and ColumnATable2 being the description.
I tried this but got an error...
alter table dbo.CommittedTbl
add V_VendorName nvarchar(200)
where v_venkey = v_vendorno
It tells me that I have incorrect syntax... Anyone know how to accomplish this?
alter table dbo.CommittedTbl
add V_VendorName nvarchar(200);
go
update c
set c.V_VendorName = a.V_VendorName
from CommittedTbl c
join TableA a
on c.v_venkey = a.v_vendorno;
go
I'm just guessing at your structure here.
alter table 2 add column A <some_type>;
update table2 set column A = (select column_A from table2 where v_venkey = v_vendorno);
Your names for tables and columns are a bit confusing but I think that should do it.
There is no WHERE clause for an ALTER TABLE statement. You will need to add the column (your first two lines), and then insert rows based upon a relationship you define between the two tables.
ALTER TABLE syntax:
http://msdn.microsoft.com/en-us/library/ms190273%28v=sql.90%29.aspx
There are several languages within SQL:
DDL: Data Definition Language - this defines the schema (the structure of tables, columns, data types) - adding a column to a table affects the table definitions and all rows will have that new column (not just some rows according to a criteria)
DML: Data Manipulation Language - this affects data within a table, and inserting, updating or other changes fall into this and you can update some data according to criteria (and this is where a WHERE clause would come in)
ALTER is a DDL statement, while INSERT and UPDATE are DML statements.
The two cannot really be mixed as you are doing.
You should ALTER your table to add the column, then INSERT or UPDATE the column to include appropriate data.
Is it possible that you want a JOIN query instead? If you want to join two tables or parts of two tables you should use JOIN.
have a look at this for a start if you need to know more LINK
hope that helps!

Look Up Table in SQL

I basically have a table A with 30 million records and I want to add a column entitled "TYPE" to the table. I have a look up table B that maps a code to a color. I want to iterate through table A and compare the code in TABLE A to the code in TABLE B and then add the color to the TYPE column in table A. Is this possible? What would be the best approach to this problem? The codes in table B don't match perfectly with the actual codes in table A.
hard to say without seeing the schema or knowing the DBMS but, if it's always a the first 2 digits of the code used to look up the color, why not
UPDATE table_a SET type = SUBSTR(code, 2)
and do a JOIN normally
you could do a join like
JOIN table_b ON table_b.id = SUBSTR(table_a.code,2)
but that would hardly be performant.
Give or take issues with size of transaction, isn't it a simple ALTER TABLE to add the column and an UPDATE to fix it?
ALTER TABLE TableA ADD (Type VARCHAR(10));
UPDATE TableA
SET Type = ((SELECT Colour FROM TableB WHERE TableA.Type = TableB.Type));
The only tricky bit might be the double parentheses; they're needed in some DBMS and may not be needed in others (single parentheses may be sufficient). You may also be able to use a UPDATE with a JOIN; the syntax isn't entirely standard there, either.
Note that this mapping relies on a change of NULL to NULL being a no-op. If you have values in some rows but not all of those rows match an entry in TableB, then you need to be careful with an full-table UPDATE like that. It will set the Type for any rows in TableA for which there is no match in TableB to NULL. If that wasn't what you needed, you'd either use an UPDATE with JOIN or you'd write:
UPDATE TableA
SET Type = ((SELECT Colour FROM TableB WHERE TableA.Type = TableB.Type));
WHERE Type IN (SELECT Colour FROM TableB WHERE TableA.Type = TableB.Type);
In the current case, where the column is newly added and therefore contains NULL anyway, there is no harm done omitting the WHERE clause on the UPDATE itself.
You can do the update just by looking at the first characters of the code in table B, as in the following statement:
update table_a
set table_a.type = table_b.type
from table_b
where table_b.code = substr(table_a.code, 1, length(table_b.code))
This may be a bit slow, since you cannot use any indexes to speed it up. However, if table_b is small, then the performance may be acceptable.

SQL: I need to take two fields I get as a result of a SELECT COUNT statement and populate a temp table with them

So I have a table which has a bunch of information and a bunch of records. But there will be one field in particular I care about, in this case #BegAttField# where only a subset of records have it populated. Many of them have the same value as one another as well.
What I need to do is get a count (minus 1) of all duplicates, then populate the first record in the bunch with that count value in a new field. I have another field I call BegProd that will match #BegAttField# for each "first" record.
I'm just stuck as to how to make this happen. I may have been on the right path, but who knows. The SELECT statement gets me two fields and as many records as their are unique #BegAttField#'s. But once I have them, I haven't been able to work with them.
Here's my whole set of code, trying to use a temporary table and SELECT INTO to try and populate it. (Note: the fields with # around the names are variables for this 3rd party app)
CREATE TABLE #temp (AttCount int, BegProd varchar(255))
SELECT COUNT(d.[#BegAttField#])-1 AS AttCount, d.[#BegAttField#] AS BegProd
INTO [#temp] FROM [Document] d
WHERE d.[#BegAttField#] IS NOT NULL GROUP BY [#BegAttField#]
UPDATE [Document] d SET d.[#NumAttach#] =
SELECT t.[AttCount] FROM [#temp] t INNER JOIN [Document] d1
WHERE t.[BegProd] = d1.[#BegAttField#]
DROP TABLE #temp
Unfortunately I'm running this script through a 3rd party database application that uses SQL as its back-end. So the errors I get are simply: "There is already an object named '#temp' in the database. Incorrect syntax near the keyword 'WHERE'. "
Comment out the CREATE TABLE statement. The SELECT INTO creates that #temp table.