Update Column from Separate Table When Not Match By Source - sql-server

I am using SQL Management Studio 2012.
I would like to update a field from a table that is not within the Target/Source relationship in a Store Procedure using a TRIGGER to update records from a View ([dbo].ActivityView tv) to an editable table ([dbo].ActivityTracker t). Records fall in and out of the View based on a [COMPLETION] date field. If the [COMPLETION] date value is past the end of the Quarter, it drops out of the View but triggers a "Won't Be Complete" in the Target's [COMPLETION] column. However, when this happens, I can't see when that update timestamp to the [COMPLETION] field took place since it is no longer within the View. The value exists in "THISOTHERTABLE" the View is based off.
Therefore, I would like to update the field in the Target from "THISOTHERTABLE" if possible.
MERGE [dbo].[ActivityTracker] t --TARGET
USING [dbo].[ActivityView] tv --SOURCE
on tv.ID = t.ID
WHEN MATCHED THEN
UPDATE
SET t.ID = tv.ID,
Do Stuff...
WHEN NOT MATCHED BY TARGET THEN
Do Stuff...
WHEN NOT MATCHED BY SOURCE THEN
Set t.TIMESTAMP = (select distinct o.TIMESTAMP from [dbp].THISOTHERTABLE o where t.ID = o.ID) END
"THISOTHERTABLE" has multiple records for the ID field, so I would have to select distinct TIMESTAMP to get only a single value for the unique ID in the TARGET table. However, THISOTHERTABLE already has only the MAX(TIMESTAMP) for TIMESTAMP so no need to do the MAX. The TARGET table has only one unique record for each ID. Is it possible to write an UPDATE subquery like I have shown in the last line of example code?

Related

SQL Server Trigger to alter different table

I’m trying to create a trigger to change the value of a column in table B if it finds the information in a column in table A.
An example of my database is below:
[TableA],
itemID
[TableB],
itemID
itemInStock
Once a user creates an entry in Table A declaring an itemID, the trigger needs to change the TableB.itemInStock column to ‘Yes’
I’m still learning SQL so excuse me if I’ve missed something, let me know if you need any more info.
I understand there are better ways of doing this but I've been told I need to do this using a trigger.
I've attempted a few different things, but as it stands nothing is working, below is the current solution I have however this updates all itemInStock rows to 'Yes', where as I only want the ones to update where the TableB.itemID matches the itemID entered in TableA.
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA] FOR
INSERT
AS
BEGIN
UPDATE [dbo].[TableB] set itemInStock = 'Yes' WHERE
TableB.itemID = itemID
END
Two problems -
you're not looking at the Inserted pseudo table which contains the
newly inserted rows
you're assuming the trigger is called once per row - this is not the
case, the trigger is called once per statement and the Inserted
pseudo table will contain multiple rows - and you need to deal with
that
So, your code should look like this -
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA]
FOR INSERT
AS
UPDATE TB
SET itemInStock = 'Yes'
FROM [dbo].[TableB] TB JOIN inserted I
on TB.itemID = I.itemID

Update row_number value in view joined to different table

I created a view in SQL Server that includes a row_number() function. The table referenced in the view contains every record in my database and enumerates records based on duplicate instances of a composite ID. For example:
row_number() over (
partition by
composite_id
order by
sample_value) as rownum
The issue is that whenever I join this view against another table (or filter rows based on a WHERE clause), the row number nevertheless always returns the value that would be returned for the full table referenced in the view. Instead, I'd like the row number to update depending on the records that are ultimately returned in the eventual result set.
For example:
select *
from my_created_view a
where a.sample_value in ('a','b','c')
or
select *
from my_created_view a
inner join subset_of_data b on a.sample_value = b.sample_value
...where either query above would result in a smaller number of records than are contained in the full original table and the resulting set of composite_id would sometimes contain only one instance. In cases where the result set contains only one instance of composite_id, I'd like that row to receive a value of 1.
Is this possible? Or does row numbering within a view create a row number that's tied only to the query within the created view?
Thanks in advance for any light you can shed here!

Merge query using two tables in SQL server 2012

I am very new to SQL and SQL server, would appreciate any help with the following problem.
I am trying to update a share price table with new prices.
The table has three columns: share code, date, price.
The share code + date = PK
As you can imagine, if you have thousands of share codes and 10 years' data for each, the table can get very big. So I have created a separate table called a share ID table, and use a share ID instead in the first table (I was reliably informed this would speed up the query, as searching by integer is faster than string).
So, to summarise, I have two tables as follows:
Table 1 = Share_code_ID (int), Date, Price
Table 2 = Share_code_ID (int), Share_name (string)
So let's say I want to update the table/s with today's price for share ZZZ. I need to:
Look for the Share_code_ID corresponding to 'ZZZ' in table 2
If it is found, update table 1 with the new price for that date, using the Share_code_ID I just found
If the Share_code_ID is not found, update both tables
Let's ignore for now how the Share_code_ID is generated for a new code, I'll worry about that later.
I'm trying to use a merge query loosely based on the following structure, but have no idea what I am doing:
MERGE INTO [Table 1]
USING (VALUES (1,23-May-2013,1000)) AS SOURCE (Share_code_ID,Date,Price)
{ SEEMS LIKE THERE SHOULD BE AN INNER JOIN HERE OR SOMETHING }
ON Table 2 = 'ZZZ'
WHEN MATCHED THEN UPDATE SET Table 1.Price = 1000
WHEN NOT MATCHED THEN INSERT { TO BOTH TABLES }
Any help would be appreciated.
http://msdn.microsoft.com/library/bb510625(v=sql.100).aspx
You use Table1 for target table and Table2 for source table
You want to do action, when given ID is not found in Table2 - in the source table
In the documentation, that you had read already, that corresponds to the clause
WHEN NOT MATCHED BY SOURCE ... THEN <merge_matched>
and the latter corresponds to
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
Ergo, you cannot insert into source-table there.
You could use triggers for auto-insertion, when you insert something in Table1, but that will not be able to insert proper Shared_Name - trigger just won't know it.
So you have two options i guess.
1) make T-SQL code block - look for Stored Procedures. I think there also is a construct to execute anonymous code block in MS SQ, like EXECUTE BLOCK command in Firebird SQL Server, but i don't know it for sure.
2) create updatable SQL VIEW, joining Table1 and Table2 to show last most current date, so that when you insert a row in this view the view's on-insert trigger would actually insert rows to both tables. And when you would update the data in the view, the on-update trigger would modify the data.

SSIS : delete rows after an update or insert

Here is the following situation:
I have a table of StudentsA which needs to be synchronized with another table, on a different server, StudentsB. It's a one-way sync from A to B.
Since the table StudentsA can hold a large number of rows, we have a table called StudentsSync (on the input server) containing the ID of StudentsA which have been modified since the last copy from StudentsA to StudentsB.
I made the following SSIS Data Flow task:
The only problem is that I need to DELETE the row from StudentsSync after a successful copy or update. Something like this:
Any idea how this can be achieved?
It can be achieved using 3 methods
1.If your target table in OutputDB has TimeStamp columns such as Create and modified TimeStamp then rows which have got updated or inserted can be obtained by writing a simple query. You need to write the below query in the execte sql task in Control Flow to delete those rows in Sync Table .
Delete from SyncTable
where keyColumn in (Select primary_key from target
where ModifiedTimeStamp >= GETDATE() or (ModifiedTimeStamp is null
and CreateTimeStamp>=GETDATE()))
I assume StudentsA's primary key is present in Sync table along with primary key of Target table. The above condition basically checks, if a new row is added then CreateTimeStamp column will have current date and modifiedTimeStamp will be null else if the values are updated then the modifiedTimeStamp will have current date
The above query will work if you have TimeStamp columns in your target table which i feel should be there if your loading data into Data Warehouse
2.You can use MERGE syntax to perform the update and insert in Control Flow with Execute SQL Task.No need to use Data Flow Task .The below query can be used even if you don't have any TimeStamp columns
DECLARE #Output TABLE ( ActionType VARCHAR(20), SourcePrimaryKey INT)
MERGE StudentsB AS TARGET
USING StudentsA AS SOURCE
ON (TARGET.CommonColumn = SOURCE.CommonColumn)
WHEN MATCHED
THEN
UPDATE SET TARGET.column = SOURCE.Column,TARGET.ModifiedTimeStamp=GETDATE()
WHEN NOT MATCHED BY TARGET THEN
INSERT (col1,col2,Col3)
VALUES (SOURCE.col1, SOURCE.col2, SOURCE.Col3)
OUTPUT $action,
INSERTED.PrimaryKey AS SourcePrimaryKey INTO #Output
Delete from SyncTable
where PrimaryKey in (Select SourcePrimaryKey from #Output
where ActionType ='INSERT' or ActionType='UPDATE')
The code is not tested as i'm running out of time .but at-least it should give you a fair idea how to proceed . .For furthur detail on MERGE syntax read this and this
3.Use Multicast Component to duplicate the dataset for Insert and Update .Connect a MULTICAST to lookmatch output and another multicast to Lookup No match output
Add a task after "Update existing entry" and after "Insert new entry" to add the student ID to a variable which will contain the list of IDs to delete.
Enclose all of the tasks in a sequence container.
After the sequence container executes add a task to delete all the records from the sync table that are in that variable you've been populating.

How do I Iterate through a small set of records and retrieve records that match criteria set in each record

I have a table tblCriteria that contains a small (<20) set of records. Each record has a field of criteria.
I want SQL to move through these records when requested tblFilterRun, filter the main table tblRecords (~5000 records) and then insert some key fields from the matching records into another table tblFilterResults.
tblCriteria (CriteriaID, CriteriaText)
tblFilterRun (FilterRunID, FilterRunDate)
tblFilterResults (FilterResultsID, FilterRunID, RecordID, Ref, CustomerID, SupplierID
tblRecords (RecordID, CustomerID, SupplierID...)
Previously I would have created something in Access to iterate through each tblCriteria record, but I would like a purely server solution. I've heard cursors mentioned (usually at the same time as a profanity), what are my options?
It's not really clear what you need to do with the records in tblCriteria, but can you created a UDF that would do the work of processing one record? Then you can call it on every record using one query like
SELECT *
FROM tblCriteria
CROSS APPLY dbo.udf_yourFunction(parameter1, parameter2, etc)

Resources