Merge statement for stocks using three tables - sql-server

Here is the SQL Query:
MERGE tblProductsSold
USING tblOrders on tblOrders.OrderID = tblProductsSold.txtOrderID
WHEN NOT MATCHED THEN
Insert ( txtOrderID, txtOrderdate, txtPartno, txtQty)
values
(SELECT tblItemsOnOrder.txtOrderID,
tblOrders.txtDateTime,
tblItemsOnOrder.txtPartNO,
tblItemsOnOrder.txtQTY
FROM tblOrders INNER JOIN tblItemsOnOrder
ON tblOrders.OrderID = tblItemsOnOrder.txtOrderID
WHERE tblOrders.txtIsConfirmed = '1'
)
OUTPUT $action ;
Desired Result: need to import orders with Products that are not already in the tblProductsSold table

You cannot approach it like you are doing it right now.
The MERGE statement merges two tables - the two tables you define in the header - the source table and the target table.
Right now, you're using tblOrders as your source, and tblProducts as your target. That alone seems odd - you're trying to merge orders into products? Doesn't seem very fitting...
Once you've defined your source and target table - you stat comparing which rows from the source are present in the target (or not). If a given row from your source is not present in the target - then you can insert its values into the target table.
But that only works for direct column values from the source table! You cannot go out and do subqueries into other tables as you're trying to do!
So I believe what you really should do is this:
as your source - have a view that lists the products found in your orders - the products (not the orders per se)
then compare your Products table to this view - if your orders happen to have any products that aren't present in the base Products table - insert them.
So you'd need something like:
MERGE tblProductsSold AS Target
USING (SELECT tblItemsOnOrder.txtOrderID, tblOrders.txtDateTime,
tblItemsOnOrder.txtPartNO, tblItemsOnOrder.txtQty
FROM tblOrders
INNER JOIN tblItemsOnOrder ON tblOrders.OrderID = tblItemsOnOrder.txtOrderID
WHERE tblOrders.txtIsConfirmed = '1') AS Source
ON Source.OrderID = Target.txtOrderID
WHEN NOT MATCHED THEN
INSERT (txtOrderID, txtOrderdate, txtPartno, txtQty)
VALUES (Source.OrderID, Source.txtDateTime, Source.txtPartNo, Source.txtQty)
OUTPUT $action ;

Related

Insert New Records Into Table Using If/Else Statement

I have two SQL Server tables where I need to add records from one table to the next. If the unique identifier already exists in the target table, then update the record to the data coming from source table - If the unique identifier doesn't exist, then insert the entire new record into the target table.
I seem to have gotten the initial part to work where I update the records in target table but the the part where I would INSERT new records does not seem to be working.
if exists (
select 1
from SCM_Top_Up_Operational O
join SCM_Top_Up_Rolling R ON O.String = R.string
)
begin
update O
set O.Date_Added = R.Date_Added,
O.Real_Exfact = R.Real_Exfact,
O.Excess_Top_Up = R.Excess_Top_Up
from SCM_Top_Up_Operational O
join SCM_Top_Up_Rolling R on O.String = R.String
where O.String = R.string and R.date_added > O.date_added
end
else
begin
insert into SCM_Top_Up_Operational (String,Date_Added,Real_Exfact,Article_ID,Excess_Top_Up,Plant)
select String,Date_Added,Real_Exfact,Article_ID,Excess_Top_Up,Plant
from SCM_Top_Up_Rolling
end
If I followed you correctly, you should be able to solve this with a single SQL query, using SQL Server MERGE syntax, available since SQL Server 2008.
From the documentation:
Runs insert, update, or delete operations on a target table from the results of a join with a source table. For example, synchronize two tables by inserting, updating, or deleting rows in one table based on differences found in the other table.
Consider the following query:
MERGE
SCM_Top_Up_Operational O
USING SCM_Top_Up_Rolling R ON (O.String = R.string)
WHEN MATCHED
THEN UPDATE SET
O.Date_Added = R.Date_Added,
O.Real_Exfact = R.Real_Exfact,
O.Excess_Top_Up = R.Excess_Top_Up
WHEN NOT MATCHED BY TARGET
THEN INSERT ( String, Date_Added, Real_Exfact, Article_ID, Excess_Top_Up, Plant)
VALUES (R.String, R.Date_Added, R.Real_Exfact, R.Article_ID, R.Excess_Top_Up, R.Plant)

TSQL - Copy data from one table to another

I'm copying the contents of a table into another identical table. But there are already data in the destination table.
Some data in the destination table has the same code as the source table.
Is it possible to skip the duplicates and not to block the insertion for the rest of the data without it failing?
insert into [DB2].[dbo].[MAN] values([MAN],[DES])
SELECT [MAN]
,[DES]
FROM [DB1].[dbo].[MAN]
You can use NOT EXISTS :
INSERT INTO [DB2].[dbo].[MAN] ([MAN], [DES])
SELECT M.[MAN], M.[DES]
FROM [DB1].[dbo].[MAN] AS M
WHERE NOT EXISTS (SELECT 1 FROM [DB2].[dbo].[MAN] M1 WHERE M1.COL = M.COL);
You need to change the M1.COL = M.COL with your actual column name from which you can identify the duplicate values.
If you have your unique col then you can go like this.
insert into [DB2].[dbo].[MAN] values([MAN],[DES])
SELECT [MAN]
,[DES]
FROM [DB1].[dbo].[MAN] WHERE uniqueCol NOT IN (SELECT uniqueCol FROM [DB2].[dbo].[MAN])
Otherwise append few columns to get unique one and compare like that.

SQL Server FullText Search with Weighted Columns from Previous One Column

In the database on which I am attempting to create a FullText Search I need to construct a table with its column names coming from one column in a previous table. In my current implementation attempt the FullText indexing is completed on the first table Data and the search for the phrase is done there, then the second table with the search results is made.
The schema for the database is
**Players**
Id
PlayerName
Blacklisted
...
**Details**
Id
Name -> FirstName, LastName, Team, Substitute, ...
...
**Data**
Id
DetailId
PlayerId
Content
DetailId in the table Data relates to Id in Details, and PlayerId relates to Id in Players. If there are 1k rows in Players and 20 rows in Details, then there are 20k rows in Data.
WITH RankedPlayers AS
(
SELECT PlayerID, SUM(KT.[RANK]) AS Rnk
FROM Data c
INNER JOIN FREETEXTTABLE(dbo.Data, Content, '"Some phrase like team name and player name"')
AS KT ON c. DataID = KT.[KEY]
GROUP BY c.PlayerID
)
…
Then a table is made by selecting the rows in one column. Similar to a pivot.
…
SELECT rc.Rnk,
c.PlayerID,
PlayerName,
TeamID,
…
(SELECT Content FROM dbo.Data data WHERE DetailID = 1 AND data.PlayerID = c.PlayerID) AS [TeamName],
…
FROM dbo.Players c
JOIN RankedPlayers rc ON c. PlayerID = rc. PlayerID
ORDER BY rc.Rnk DESC
I can return a ranked table with this implementation, the aim however is to be able to produce results from weighted columns, so say the column Playername contributes to the rank more than say TeamName.
I have tried making a schema bound view with a pivot, but then I cannot index it because of the pivot. I have tried making a view of that view, but it seems the metadata is inherited, plus that feels like a clunky method.
I then tried to do it as a straight query using sub queries in the select statement, but cannot due to indexing not liking sub queries.
I then tried to join multiple times, again the index on the view doesn't like self-referencing joins.
How to do this?
I have come across this article http://developmentnow.com/2006/08/07/weighted-columns-in-sql-server-2005-full-text-search/ , and other articles here on weighted columns, however nothing as far as I can find addresses weighting columns when the columns were initially row data.
A simple solution that works really well. Put weight on the rows containing the required IDs in another table, left join that table to the table to which the full text search had been applied, and multiply the rank by the weight. Continue as previously implemented.
In code that comes out as
DECLARE #Weight TABLE
(
DetailID INT,
[Weight] FLOAT
);
INSERT INTO #Weight VALUES
(1, 0.80),
(2, 0.80),
(3, 0.50);
WITH RankedPlayers AS
(
SELECT PlayerID, SUM(KT.[RANK] * ISNULL(cw.[Weight], 0.10)) AS Rnk
FROM Data c
INNER JOIN FREETEXTTABLE(dbo.Data, Content, 'Karl Kognition C404') AS KT ON c.DataID = KT.[KEY]
LEFT JOIN #Weight cw ON c.DetailID = cw.DetailID
GROUP BY c.PlayerID
)
SELECT rc.Rnk,
...
I'm using a temporary table here for evidence of concept. I am considering adding a column Weights to the table Details to avoid an unnecessary table and left join.

Sql Server - How compare hash of two rows in merge

I have several working tables that I am merging together into one final table that will be used for display. If the display table does not contain the primary key compiled from the working tables (hereafter called src)then I insert the row into display. This works fine, the next part is confusing to me.
If the primary key is already in display I only want to update the display row if the src row has the same primary key but at least one column is different from the display row. I'd like to implement this using the HASHBYTES() method using the MD5 algorithm.
From msdn, the syntax should look like this: HASHBYTES('MD5', {#variable | 'string'})
I want to be able to do something like this in my merge statement:
WHEN MATCHED AND HASHBYTES('MD5', display) != HASHBYTES('MD5', src) THEN ...(stuff)
How do I complete the HASHBYTES function?
Here is my current merge statement
MERGE dbo.DisplayCases AS display
USING (SELECT CaseId, Title, projects.ProjectName, categories.CategoryTitle, Root, milestones.MilestoneName,
milestones.MilestoneDate, Priority, statuses.StatusTitle, EstimatedHours, ElapsedHours, personAssigned.Name as AssignedTo,
personResolved.Name as ResolvedBy, cases.IsResolved, IsOpen, Opened, Resolved, Uri, ResolveUri,
OutlineUri, SpecUri, ParentId, Backlog
FROM fogbugz.Cases cases
JOIN fogbugz.Projects projects ON cases.ProjectId = projects.ProjectId
JOIN fogbugz.Categories categories ON cases.CategoryId = categories.CategoryId
JOIN fogbugz.Milestones milestones ON cases.MilestoneId = milestones.MilestoneId
JOIN fogbugz.Statuses statuses ON cases.Status = statuses.StatusId
JOIN fogbugz.People personAssigned ON cases.AssignedTo = personAssigned.Id
LEFT JOIN fogbugz.People personResolved ON cases.ResolvedBy = personResolved.Id
) as src
ON display.CaseId = src.CaseId
WHEN NOT MATCHED THEN
INSERT(CaseId, CaseTitle, ProjectName, CategoryTitle, RootId, MilestoneName, MilestoneDate, Priority,
StatusTitle, EstHrs, ElapsedHrs, AssignedTo, ResolvedBy, IsOpen, IsResolved, Opened, Resolved, Uri,
ResolveUri, OutlineUri, Spec, ParentId, Backlog)
VALUES(src.CaseId, src.Title, src.ProjectName, src.CategoryTitle, src.Root, src.MilestoneName,
src.MilestoneDate, src.Priority, src.StatusTitle, src.EstimatedHours, src.ElapsedHours,
src.AssignedTo, src.ResolvedBy, src.IsResolved, src.IsOpen, src.Opened, src.Resolved,
src.Uri, src.ResolveUri, src.OutlineUri, src.SpecUri, src.ParentId, src.Backlog);
From Martin Smith's comment...
You could do WHEN MATCHED AND EXISTS(SELECT Source.* EXCEPT SELECT Target.*) THEN UPDATE ...

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.

Resources