Multipart column names in update statement with select - tsql

I'm sure this could be a duplicate but I can't seem to find the right search phrase.
Given a table in a named schema (i.e. not dbo) requires you include the schema name in the statement. So previously I'd have simply written it as so:
UPDATE [Schema].[Table1]
SET [AColumn] =
(
SELECT [SomeColumn]
FROM [Schema].[Table2]
WHERE [Schema].[Table2].[SameColumnName] = [Schema].[Table1].[SameColumnName]
);
But since More than two-part column name is deprecated, I need to find a new way to do this which is future proof. I have come up with 2 options, firstly using an alias:
UPDATE [Alias1]
SET [AColumn] =
(
SELECT [SomeColumn]
FROM [Schema].[Table2] [Alias2]
WHERE [Alias2].[SameColumnName] = [Alias1].[SameColumnName]
)
FROM [Schema].[Table1] [Alias1];
The second way is the one I'm really having trouble finding out if it's truly VALID T-Sql:
UPDATE [Schema].[Table1]
SET [AColumn] =
(
SELECT [SomeColumn]
FROM [Schema].[Table2]
WHERE [Table2].[SameColumnName] = [Table1].[SameColumnName]
);
I have tested both and they work, so my question is, is the second completely valid and normal to use just the table name without the Schema in this sense or should I rather opt for the slightly more verbose Alias?

As I said in my comment, alias your objects.
SELECT MT.MyColumn,
YT.MyColumn
FROM dbo.MyTable MT
JOIN so.YourTable YT ON MT.ID = YT.fID
WHERE YT.[name] = N'Jane';
If you're performing an UPDATE, then specify the alias of the object to Update:
UPDATE MT
SET MyColumn = YT.MyColumn --Column on the left side of the SET will always reference the table being updated
FROM dbo.MyTable MT
JOIN so.YourTable YT ON MT.ID = YT.fID
WHERE YT.[name] = N'Jane';

Related

Postgresql - Rule with On Conflict Statement

I have a table in postgres with columns link(PK), person, places and date. I would like to create a rule that when insert is command is issued from my backend program then if there is a conflict on the link column it would do an upsert ( update the person, places and date) columns for the same link. I cannot figure out the format of the rule. Below is pseudo code of what I am looking for.
Create Rule rssmodel as on
INSERT into public.rssmodel
On conflict (link)
do UPDATE public.rssmodel
set person = data, places=data, date=data
You could do something like this to achieve that:
CREATE RULE rssmodel_insert AS ON
INSERT TO public.rssmodel
WHERE EXISTS (SELECT 1 from rssmodel where NEW.link = link)
DO INSTEAD
UPDATE public.rssmodel
SET person = NEW.person, places = NEW.places, date = NEW.date WHERE link = NEW.link;

SQL update statements updates wrong fields

I have the following code in Postgres
select op.url from identity.legal_entity le
join identity.profile op on le.legal_entity_id =op.legal_entity_id
where op.global_id = '8wyvr9wkd7kpg1n0q4klhkc4g'
which returns 1 row.
Then I try to update the url field with the following:
update identity.profile
set url = 'htpp:sam'
where identity.profile.url in (
select op.url from identity.legal_entity le
join identity.profile op on le.legal_entity_id =op.legal_entity_id
where global_id = '8wyvr9wkd7kpg1n0q4klhkc4g'
);
But the above ends up updating more than 1 row, actually all of the rows of the identity table.
I would assume since the first postgres statement returns one row, only one row at most can be updated, but I am getting the wrong effect where all of the rows are being updated. Why ?? Please help a nubie fix the above update statement.
Instead of using profile.url to identify the row you want to update, use the primary key. That is what it is there for.
So if the primary key column is called id, the statement could be modified to:
UPDATE identity.profile
SET ...
WHERE identity.profile.id IN (SELECT op.id FROM ...);
But you can do this much simpler in PostgreSQL with
UPDATE identity.profile op
SET url = 'htpp:sam'
FROM identity.legal_entity le
WHERE le.legal_entity_id = op.legal_entity_id
AND le.global_id = '8wyvr9wkd7kpg1n0q4klhkc4g';

What does a column assignment using an aggregate in the columns area of a select do?

I'm trying to decipher another programmer's code who is long-gone, and I came across a select statement in a stored procedure that looks like this (simplified) example:
SELECT #Table2.Col1, Table2.Col2, Table2.Col3, MysteryColumn = CASE WHEN y.Col3 IS NOT NULL THEN #Table2.MysteryColumn - y.Col3 ELSE #Table2.MysteryColumn END
INTO #Table1
FROM #Table2
LEFT OUTER JOIN (
SELECT Table3.Col1, Table3.Col2, Col3 = SUM(#Table3.Col3)
FROM Table3
INNER JOIN #Table4 ON Table4.Col1 = Table3.Col1 AND Table4.Col2 = Table3.Col2
GROUP BY Table3.Col1, Table3.Col2
) AS y ON #Table2.Col1 = y.Col1 AND #Table2.Col2 = y.Col2
WHERE #Table2.Col2 < #EnteredValue
My question, what does the fourth column of the primary selection do? does it produce a boolean value checking to see if the values are equal? or does it set the #Table2.MysteryColumn equal to some value and then inserts it into #Table1? Or does it just update the #Table2.MysteryColumn and not output a value into #Table1?
This same thing seems to happen inside of the sub-query on the third column, and I am equally at a loss as to what that does as well.
MysteryColumn = gives the expression a name also called a column alias. The fact that a column in the table#2 also has the same name is besides the point.
Since it uses INTO syntax it also gives the column its name in the resulting temporary table. See the SELECT CLAUSE and note | column_alias = expression and the INTO CLAUSE

Updating two tables with same data where there is no relationship (PK,FK) between those tables

update Claim
set first_name = random_name(7),
Last_name = random_name(6),
t2.first_name=random_name(7),
t2.last_name=random_name(6)
from Claim t1
inner join tbl_ecpremit t2
on t1.first_name = t2.first_name
I am getting below error
column "t2" of relation "claim" does not exist
You can do this with a so-called data-modifying CTE:
WITH c AS (
UPDATE claim SET first_name = random_name(7), last_name = random_name(6)
WHERE <put your condition here>
RETURNING *
)
UPDATE tbl_ecpremit SET last_name = c.last_name
FROM c
WHERE first_name = c.first_name;
This assumes that random_name() is a function you define, it is not part of PostgreSQL afaik.
The nifty trick here is that the UPDATE in the WITH query returns the updated record in the first table using the RETURNING clause. You can then use that record in the main UPDATE statement to have exactly the same data in the second table.
This is all very precarious though, because you are both linking on and modifying the "first_name" column with some random value. In real life this will only work well if you have some more logic regarding the names and conditions.

How to find primary key on a table in DB2?

I am unable to fetch primary key in DB2. I used following code but It is not working for me.
SELECT TBCREATOR, TBNAME, NAME, KEYSEQ
FROM SYSIBM.SYSCOLUMNS
WHERE TBCREATOR = 'DSN8710'
AND TBNAME = 'EMPLOYEE'
AND KEYSEQ > 0
ORDER BY KEYSEQ;
And what is the means of TBCREATOR in this code and how to modified TBCREATOR value according to my case?
I'll answer your last question first. creator is sometimes referred to as schema. If you're familiar with Oracle, this is roughly analogous to a database user (though not exactly).
As far as getting the "primary key" information, you probably want to know which index is the "clustering" index (which is what usually, but not always, determines the physical ordering of the rows on disk).
How you find the clustering index depends on the platform you're running:
Mainframe (z/OS):
SELECT
RTRIM(name) AS index_name
,RTRIM(creator) AS index_schema
,uniquerule
,clustering
FROM sysibm.sysindexes
WHERE tbname = #table
AND tbcreator = #schema
AND clustering = 'Y'
Then, to see the actual columns in that index, you perform this query:
SELECT colname AS name
FROM sysibm.sysindexes a
JOIN sysibm.syskeys b
ON a.name = b.ixname
AND a.tbcreator = b.ixcreator
WHERE a.name = #index_name
AND a.tbcreator = #index_schema
ORDER BY COLSEQ
Linux/Unix/Windows:
SELECT
RTRIM(indname) AS index_name
,RTRIM(indschema) AS index_schema
,uniquerule
,indextype
FROM syscat.indexes
WHERE tabname = #table
AND tabschema = #schema
AND indextype = 'CLUS'
Then, to see the actual columns in that index, you perform this query:
SELECT colnames as name
FROM sysibm.sysindexes
WHERE name = #index_name
AND tbcreator = #index_schema
ORDER BY NAME
LUW returns the list of columns as one string, delimited by +, which is kind of weird...