Populating table from table of value - sql

I've got a largish Oracle table (30M rows) which contains three columns: ID, fieldname, value. I need a query that will update the target table (which contains 93 columns) from the source data. So if the first row of the source table is 1,'first_name','Robert' then this will update the row where ID=1 updating first_name column with the value 'Robert'.
Is this even possible with a query or do I need to process it with another tool?

Hmmm. You can do this with a query. I would suggest building an index on the first table on id, fieldname, value and then running the following update 93 times:
update targettable tt
set field1 = (select max(value) from sourcetable st where st.id = tt.id and st.fieldname = 'field1')
where exists (select 1 from sourcetable st where st.id = tt.id and st.fieldname = 'field1');
You can actually write this all as one query, but it gets complicated to handle rows where only some fields are updated.

Related

Copying the rows within the same table

I need to move what's been appended at the end of my table to its very beginning, however
the same record is being copied into destination.
In other words, between the ids 1 and 3567 I only have the record from the id 3567 repeated until the end. I believe that my outer and even inner sub-query lacks something ?
Thanks for the hint
Query:
UPDATE dbo.TABLE
SET Xwgs = dt.Xwgs, Ywgs = dt.Ywgs
FROM
(
SELECT
Xwgs,
Ywgs
FROM dbo.TABLE
WHERE
Id BETWEEN 3567 AND 7243
) dt
WHERE
Id BETWEEN 1 AND 3566
Is this what you want?
update t
set xwgs = dt.xwgs, ywgs = dt.ywgs
from mytable t
inner join (
select xwgs, ywgs
from mytable
where id between 3567 and 7243
) dt
on t.id = dt.id - 3566
The main difference with your query is that it properly correlates the target table and the derived table.
Note that this does not actually move the rows; all it does is copy the values from the upper bucket to the corresponding value in the lower bucket.
You know that You can always sort Your table with ORDER BY id DESC right?
Sometimes its needed do something strange. I do it like that:
Copy the whole table into a temp table (it may be #temporary table)
Drop or Truncate or Delete records from that table
Insert those records again from my temp table
Drop temp table
But an UPDATE is also a solution.
Tip: You can allow inserting values into identity (autoincreament) id column with SET IDENTITY_INSERT
SELECT *
INTO tmp__MyTable -- this will create a new table
FROM MyTable
ORDER BY id
DELETE FROM dbo.MyTable -- will throw an error on foreign keys conflicts
INSERT INTO MyTable (col,col2) -- column list here
SELECT col,col2
FROM tmp__MyTable
ORDER BY id DESC
-- or something like that:
-- ORDER BY CASE WHEN id <= 3566 THEN -id ELSE id END
-- DROP TABLE tmp__MyTable

SQL - trigger select into after update/insert

i have a table called Audit_Data, and from time to time there is an update coming. Every single update consists of around 300 rows (around 20 columns per row), and all of the rows from the same update share the same Audit_ID.
I have a select, that pulls out only this data, which is relevant for me. It basically transform the 300x20 field data into one row of data.
Is there a way to create a SQL trigger, that would perform the select on the updated Audit_Data table, and insert selected data into table named Audit_Final?
This is my select statement that i use to pull out the relevant data:
SELECT main.Audit_ID
,main.Item_19
,main.Item_1
,main.Item_7
,main.Item_8
,Item_17
,main.Item_13
,macaddr.Item_2
,macaddr.Item_16
,t1.Item_1
FROM dbo.[Audit_Data] AS main
LEFT JOIN
(
SELECT Audit_ID, Item_2, Item_16
FROM dbo.[Audit_Data] AS macaddr
WHERE
(Item_2 NOT LIKE 'Hyper-V%')
AND (Item_17 = 'connected')
AND (Item_18 IN ('10000Mbps', '1000MBps') OR ITEM_9 IS NOT NULL AND ITEM_10 IS NOT NULL)
AND (Item_18 != '100Mbps')
) macaddr ON main.Audit_ID = macaddr.Audit_ID
LEFT JOIN
(
SELECT Audit_ID, Category_ID, Item_1, Record_ordinal
FROM dbo.[Audit_Data] AS t1
WHERE
Item_1 = 'Automatyczna konfiguracja sieci przewodowej' OR Item_1 = 'dot3svc' OR Item_1 = 'Wired AutoConfig'
AND Item_3 = 'Running'
AND Category_ID = '4100'
) t1 ON main.Audit_ID = t1.Audit_ID
WHERE
main.Record_Ordinal = '2'
ORDER BY main.Audit_ID
Based on authors comment this is what is required here:
CREATE TRIGGER [TR_Audit_Data] ON [Audit_Data]
AFTER UPDATE
AS
BEGIN
INSERT INTO [Audit_Final](cloumn_1, colum_2, ... all columns you have on target table)
/*
Paste your select query here
*/
END

select from table based on values not in lookup table from single record

I need to select from table A for a column value not in LKP table. The lookup table will have a list of values stored in a column in a single record.
Eg:
Table LKP will have something like this for a column C1 having value as 'INVALID','UNKNOWN' in a single record.
Table A:
ID
---
Bulbasaur
Charizard
Sqirtle
UNKNOWN
Ash
INVALID
Table LKP:
RULE C1
---- ---
1 'UNKNOWN','INVALID'
Desired output from below code:
select * from A where ID not in (select C1 from LKP where rule=1)
ID
---
Bulbasaur
Charizard
Sqirtle
Ash
I need to select all other values from table A except the one that are available in C1 as single record.The above code is not working. I am getting all the records returned from A. Should the record value for C1 be inserted differently in LKP table? It has to be in a single record mapped to rule=1 in where condition as shown.
Please suggest.
I discourage you from using not in with a subquery. If any of the returned values are NULL, then no rows at all are returned in the query.
Does not exists fix your problem?
select a.*
from A
where not exists (select 1 from LKP where lkp.rule = 1 and lkp.c1 = a.id);
You can split and explode the csv string and then do the comparison.
with split_values as (select rule,c1,c1_split
from LKP
lateral view explode(split(c1)) tbl as c1_split
)
select * from a
where not exists (select 1 from split_values s where s.c1_split=a.id and s.rule=1)

How to determine what fields were update in an update trigger

UPDATE: Using Update_Columns() is not an answer to this question, as the fields may change in the order which will break the trigger (Update_Columns depends on the column order).
UPATE 2: I already know that the Deleted and Inserted tables hold the data. The question is how to determine what has changed without having to hard code the field names as the field names may change, or fields may be added.
Lets say I have a table with three fields.
The row already exists, and now the user updates fields 1 and 2.
How do I determine, in the Update Trigger, what the field were updated, and what the before and after values where?
I want to then log these to a log table. If there were two fields update, it should result in two rows in the history table.
Table
Id intField1 charField2 dateField3
7 3 Fred 1995-03-05
Updated To
7 3 Freddy 1995-05-06
History Table
_____________
Id IdOfRowThatWasUpdated BeforeValue AfterValue (as string)
1 7 Fred Freddy
2 7 1995-03-05 1995-05-06
I know I can use the Deleted table to Get the old values, and the inserted table to get the new values. The question however, is how to do this dynamically. In other words, the actual table has 50 columns, and I don't want to hard code 50 fields into a SQL statement, and also if the fields change, and don't want to have to worry about keeping the SQL in sync with table changes.
Greg
you can use one of my favorite XML-tricks to do this:
create trigger utr_Table1_update on Table1
after update, insert, delete
as
begin
with cte_inserted as (
select id, (select t.* for xml raw('row'), type) as data
from inserted as t
), cte_deleted as (
select id, (select t.* for xml raw('row'), type) as data
from deleted as t
), cte_i as (
select
c.ID,
t.c.value('local-name(.)', 'nvarchar(128)') as Name,
t.c.value('.', 'nvarchar(max)') as Value
from cte_inserted as c
outer apply c.Data.nodes('row/#*') as t(c)
), cte_d as (
select
c.ID,
t.c.value('local-name(.)', 'nvarchar(128)') as Name,
t.c.value('.', 'nvarchar(max)') as Value
from cte_deleted as c
outer apply c.Data.nodes('row/#*') as t(c)
)
insert into Table1_History (ID, Name, OldValue, NewValue)
select
isnull(i.ID, d.ID) as ID,
isnull(i.Name, d.Name) as Name,
d.Value,
i.Value
from cte_i as i
full outer join cte_d as d on d.ID = i.ID and d.Name = i.Name
where
not exists (select i.value intersect select d.value)
end;
sql fiddle demo
In this post:
How to refer to "New", "Old" row for Triggers in SQL server?
It is mentioned that/how you can access the original and the new values, and if you can access, you can compare them.
"INSERTED is the new row on INSERT/UPDATE. DELETED is the deleted row on DELETE and the updated row on UPDATE (i.e. the old values before the row was updated)"

I am trying to return a certain values in each row which depend on whether different values in that row are already in a different table

I'm still a n00b at SQL and am running into a snag. What I have is an initial selection of certain IDs into a temp table based upon certain conditions:
SELECT DISTINCT ID
INTO #TEMPTABLE
FROM ICC
WHERE ICC_Code = 1 AND ICC_State = 'CA'
Later in the query I SELECT a different and much longer listing of IDs along with other data from other tables. That SELECT is about 20 columns wide and is my result set. What I would like to be able to do is add an extra column to that result set with each value of that column either TRUE or FALSE. If the ID in the row is in #TEMPTABLE the value of the additional column should read TRUE. If not, FALSE. This way the added column will ready TRUE or FALSE on each row, depending on if the ID in each row is in #TEMPTABLE.
The second SELECT would be something like:
SELECT ID,
ColumnA,
ColumnB,
...
NEWCOLUMN
FROM ...
NEWCOLUMN's value for each row would depend on whether the ID in that row returned is in #TEMPTABLE.
Does anyone have any advice here?
Thank you,
Matt
If you left join to the #TEMPTABLE you'll get a NULL where the ID's don't exist
SELECT ID,
ColumnA,
ColumnB,
...
T.ID IS NOT NULL AS NEWCOLUMN -- Gives 1 or 0 or True/false as a bit
FROM ... X
LEFT JOIN #TEMPTABLE T
ON T.ID = X.ID -- DEFINE how the two rows can be related unquiley
You need to LEFT JOIN your results query to #TEMPTABLE ON ID, this will give you the ID if there is one and NULL if there isn't, if you want 1 or 0 this would do it (For SQL Server) ISNULL(#TEMPTABLE.ID,0)<>0.
A few notes on coding for performance:
By definition an ID column is unique so the DISTINCT is redundant and causes unnecisary processing (unless it is an ID from another table)
Why would you store this to a temporary table rather than just using it in the query directly?
You could use a union and a subquery.
Select . . . . , 'TRUE'
From . . .
Where ID in
(Select id FROM #temptable)
UNION
SELECT . . . , 'FALSE'
FROM . . .
WHERE ID NOT in
(Select id FROM #temptable)
So the top part, SELECT ... FROM ... WHERE ID IN (Subquery), does a SELECT if the ID is in your temptable.
The bottom part does a SELECT if the ID is not in the temptable.
The UNION operator joins the two results nicely, since both SELECT statements will return the same number of columns.
To expand on what someone else was saying with Union, just do something like so
SELECT id, TRUE AS myColumn FROM `table1`
UNION
SELECT id, FALSE AS myColumn FROM `table2`