So my website is currently pulling stock information from "J" warehouse in a database called InvWarehouse, now we want to add "JT", so that it pulls from both "J" and "JT"
We have a scheduled stored procedure called "[spc_Schedule_Update_Qty_Stock]"that runs script in the back ground updating new information to the website. When I executed the stored procedure it returned a value of 0, I'm not exactly sure what that means.
ALTER PROCEDURE [dbo].[spc_Schedule_Update_Qty_Stock]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
UPDATE item
SET QtyOnHand = CASE WHEN (inv.QtyOnHand - inv.QtyAllocated) < 0 THEN 0 ELSE (inv.QtyOnHand - inv.QtyAllocated) END--inv.QtyOnHand
FROM tb_Item item WITH (NOLOCK)
INNER JOIN [105.255.132.000].SysproCompanyA.dbo.InvWarehouse inv WITH (NOLOCK)
ON inv.StockCode = item.sCode COLLATE SQL_Latin1_General_CP1_CI_AS
WHERE inv.Warehouse in ('J','JT')
END
I expect the output of the following to be 9, if "J" has 7 belts and "JT" has 2, with what I did so far there's no change.
You have to do something like below. Your original query is doing calculation at individual warehouse level only. You have to aggregate the stocks at two warehouses and then you have to apply that for UPDATE operation.
;WITH WarehousesAvailability AS
(
SELECT inv.StockCode, Sum(inv.QtyOnHand) AS QtyOnHand, Sum(QtyAllocated) AS QtyAllocated
FROM [105.255.132.248].SysproCompanyA.dbo.InvWarehouse inv
WHERE inv.Warehouse in ('J','JT')
GROUP BY inv.StockCode
)
UPDATE item
SET QtyOnHand = CASE WHEN (inv.QtyOnHand - inv.QtyAllocated) < 0 THEN 0 ELSE (inv.QtyOnHand - inv.QtyAllocated) END--inv.QtyOnHand
FROM tb_Item item
INNER JOIN WarehousesAvailability inv
ON inv.StockCode = item.sCode COLLATE SQL_Latin1_General_CP1_CI_AS
Related
I have 2 Openquerys that are just simple selects from 2 tables. My objective is to populate a single table with data from those 2 queries that basically return the same thing but with different names.
Example
1st Warehouse 1
Select * From OpenQuery ('SELECT * FROM Warehouse1')
2nd Warehouse 2
Select * From OpenQuery ('SELECT * FROM Warehouse2')
There are thousands of rows that i need to update my SQL table. Problem is, this is very expensive if i use UNION, and my question is how can achieve this for best performance possible? Also this is data from an external database so i really can't change the queries
I have to update my main table with these queries only when user access the list that shows the data
EDIT.
I wasn't very clear but both tables return same type of column
| ID | Warehouse | Ticket | Item | Qty
One belongs to Warehouse 1, the other to Warehouse 2, both have different amount of rows.
You can use inner join with update for this you need to make table alias as shown below
UPDATE A
SET A.<ColName> = B.<ColName>
from Warehouse1 A
INNER JOIN Warehouse2 B
ON A.<Id> = B.<Id>
--where if required
But why you need to UNION?
You can simply insert 2 times under a transaction.
BEGIN TRY
BEGIN TRAN T1
INSERT into mytable
--select from openquery table 1
INSERT into mytable
--select from openquery table 2
COMMIT TRAN T1
END TRY
BEGIN CATCH
---handle error
ROLLBACK TRAN T1
END CATCH
For anyone with the same problem as me. Here is the solution i came up with that suits my problem better.
I save the open query on a view since I don't need to change anything or insert in my database at all
/*************************** Views ********************************/
GO
IF OBJECT_ID('viewx_POE', 'v') IS NOT NULL
DROP VIEW viewx_POE
GO
CREATE VIEW viewx_POE AS
SELECT ET0104 AS Armazem,
ET0109 AS Localizacao,
ET0102 AS Etiqueta,
ET0101 AS Artigo,
ET0103 AS Quantidade
FROM OpenQuery(MACPAC, 'SELECT FET001.ET0104, FET001.ET0109, FET001.ET0102, FET001.ET0101, FET001.ET0103
FROM AUTO.D805DATPOR.FET001 FET001
WHERE (FET001.ET0104=''POE'') AND (FET001.ET0105=''DIS'')');
/**************************************************************************/
GO
IF OBJECT_ID('viewx_CORRICA', 'v') IS NOT NULL
DROP VIEW viewx_CORRICA
GO
CREATE VIEW viewx_CORRICA AS
SELECT GHZORI AS Armazem,
GHNEMP AS Localizacao,
LBLBNB AS Etiqueta,
GHLIB5 AS Artigo,
LBQTYD AS Quantidade
FROM OpenQuery(MACPAC, 'SELECT GA160H.LBLBNB, GA160H.GHLIB5, GA160H.GHZORI, GA160H.GHNEMP, GA160M.LBQTYD
FROM D805DATPOR.GA160H GA160H, D805DATPOR.GA160M GA160M
WHERE GA160M.LBLBNB = GA160H.LBLBNB AND (GA160H.GHZORI=''CORRICA'' AND GA160H.GHCSTA=''DIS'')');
And then when needed I select the view depending on the user rank and return whatever i need from it
GO
IF OBJECT_ID('dbo.spx_SELECT_RandomLocalizacoes') IS NOT NULL
DROP PROCEDURE spx_SELECT_RandomLocalizacoes
GO
CREATE PROCEDURE spx_SELECT_RandomLocalizacoes
#LocalizacoesMax int,
#Armazem int
AS
BEGIN
SET NOCOUNT ON
DECLARE #Output int
IF ( #Armazem = 'POE' )
BEGIN
SELECT TOP(10) xa.IdArmazem, vpoe.Localizacao, vpoe.Etiqueta, vpoe.Artigo, vpoe.Quantidade
FROM viewx_POE vpoe
INNER JOIN xArmazem xa
ON vpoe.Armazem = xa.Armazem
ORDER BY NEWID()
END
ELSE IF ( #Armazem = 'CORRICA' )
BEGIN
SELECT TOP(#LocalizacoesMax) * FROM viewx_CORRICA ORDER BY NEWID()
END
END
The application I work on has an audit function which woks by setting SQL triggers on certain fields. When a change is detected, the trigger fires and adds a row to an audit table indicating what field changed, type of change (update, insert, or delete) key value for changed field, and before & after values. However, changes can be made by various program modules, and i want to track which module or sub-module made a particular change. this is a multi-user concurrent application, so different users (or scripts) may be running different modules, or different instances of the same module, at the same time. Locking prevents different users from changing the same record at the same time, and is working properly.
Here is the existing trigger for one table on updates. The triggers for insert and delete, and on a second table, are all quite similar. (table and field names have been changed)
ALTER trigger [dbo].[APP_trg_AU_Ptbl1]
on [dbo].[Ptbl1] for update as
declare #ct int, #now datetime, #id int
select #ct = ##rowcount
if #ct = 0 return
select #id = s.user_identity
from SpidUser s inner join master..sysprocesses m
on m.spid = s.spid and m.login_time = s.login_time
where m.spid = ##SPID
select #id = isnull(#id, 0)
select #now = getdate()
insert AuditTbl(edit_time, edit_type, useridentity, table_name,
field_name, old_value, new_value, _fk_table, _fk_person, _fk_event)
select #now, convert(char(1),'U'), #id, 'Ptbl1',
convert(varchar(255), 'item_code'), convert(varchar(255),
deleted.item_code), convert(varchar(255), _src.item_code),
convert(int, _src._pk), convert(int, EVENT.person_id), convert(int,
EVENT.EVENT_id)
FROM deleted INNER JOIN inserted AS _src ON deleted._pk=_src._pk INNER JOIN
EVENT ON _src._fk_event=EVENT.EVENT_id
WHERE 1 = CASE
WHEN _src.item_code is null THEN
CASE WHEN deleted.item_code is null THEN 0 ELSE 1 END
ELSE CASE WHEN deleted.item_code is null THEN 1
ELSE CASE WHEN _src.item_code = deleted.item_code THEN 0 ELSE 1 END
END
END
UNION ALL select #now, convert(char(1),'U'), #id, 'Ptbl1',
'item_sequence_num', convert(varchar(255), deleted.item_sequence_num),
convert(varchar(255), _src.item_sequence_num), _src._pk, EVENT.person_id,
EVENT.EVENT_id
FROM deleted INNER JOIN inserted AS _src ON deleted._pk=_src._pk INNER JOIN
EVENT ON _src._fk_event=EVENT.EVENT_id
WHERE 1 = CASE
WHEN _src.item_sequence_num is null THEN
CASE WHEN deleted.item_sequence_num is null THEN 0 ELSE 1 END
ELSE CASE WHEN deleted.item_sequence_num is null THEN 1
ELSE CASE WHEN _src.item_sequence_num = deleted.item_sequence_num THEN 0 ELSE 1 END
END
END
I want to be able to set a string that identifies the currently active module, so that the trigger would be able to pick it up and include it when adding a record to the audit table. I can't lock a table/field combo that everyone will write to, as that would serialize all DB access and destroy concurrency and thus performance. I am not sure where I can put or expose the string so that the trigger can reliably associate it with the specific change that caused the trigger to fire.
Client sites use a mix of SQL-server 2005, 2008, and 2012, so any code must work in all of these.
Any suggestions would be welcome.
I am hoping someone can help me out of this tedium...!?
As the title suggests I have a Temp Table (create dynamically in a select statement):
SELECT *
INTO #results
FROM Table_1
CROSS APPLY ( SELECT TOP 1 *
FROM Table_2
WHERE (Table_1.ItemId = Table_2.ItemId)
ORDER BY CreatedDt DESC
)
... which as you can see uses a Sub-Query in a cross join.
Next I am trying to use this temp table #results to update a related table with its values. have tried using an update:
UPDATE a
SET a.StatusId = b.StatusId
FROM Table_1 a
INNER JOIN #results b on (a.ItemId = b.ItemId)
and with a Merge:
MERGE INTO Table_1 a
USING #results b
ON (a.ItemId = b.temId)
WHEN MATCHED THEN UPDATE SET a.StatusId = b.StatusId;
but I seem to always get a response:
Msg 512, Level 16, State 1, Procedure trg_dbo_PBITree_TreeModel_HierarchicalEscalationHistory_InsertNode,
Line 7 [Batch Start Line 11] Subquery returned more than 1 value. This
is not permitted when the subquery follows =, !=, <, <= , >, >= or
when the subquery is used as an expression.
When I query the two tables in question (#results & Table_1) they both have 1 to 1 relationships and cannot see at all where it could be hiding some kind of Subquery!?
Can anyone help quickly on this at all please? This seems to be 1-0-1 stuff and its baking my burger!
-- Edit --
I have taken a look at the Trigger mentioned in the error message as it was suggested it could be trying to handle a single row update instead of a multiple row update which is what I am doing. Nothing looking too unusual to me...?
ALTER TRIGGER [dbo].[trg_dbo_PBITree_TreeModel_HierarchicalEscalationHistory_InsertNode]
ON [dbo].[Table_1]
AFTER UPDATE
AS
BEGIN
-- NodeModelInsertOrUpdateTPH
IF ((select [Item] from inserted) = 'X')
BEGIN
UPDATE tx
SET
tx.LastUpdatedBy = i.LastUpdatedBy,
tx.LastUpdatedAt = i.LastUpdatedAt
FROM
[dbo].[Table_X] tx,
inserted i
WHERE
tx.OtherItemId = i.OtherItemId
END
END
Anyone have any ideas?
Your trigger is the issue here. Your IF statement has a query which would return more than 1 row and that exact message would be the result. You should make your trigger tolerant of multiple row operations. Here is the same logic but it can handle any number of rows being updated.
ALTER TRIGGER [dbo].[trg_dbo_PBITree_TreeModel_HierarchicalEscalationHistory_InsertNode]
ON [dbo].[Table_1]
AFTER UPDATE
AS
BEGIN
UPDATE tx
SET
tx.LastUpdatedBy = i.LastUpdatedBy,
tx.LastUpdatedAt = i.LastUpdatedAt
FROM
[dbo].[Table_X] tx
join inserted i ON tx.OtherItemId = i.OtherItemId
where i.Item = 'X'
END
I am puling a report of daily patients in a hospital. My patient_ref_master contains both old and new patients. I have taken 2 columns as new, old. I want to fetch a report in such a way that when the patient is old then the patient id should come under old column else patient id should come under new. I am binding the result of a stored procedure to a report. When I bind the result of my SP to a grid manipulating using datable in C# code it works fine. But when I try using .RDLC report I get all the patient ID's in old and new columns as well. Can I use switch case in my Stored procedure itself to filter it out. Following is my stored procedure.
ALTER PROCEDURE [dbo].[Daily_Report] '2013/08/02'
-- Add the parameters for the stored procedure here
-- Add the parameters for the stored procedure here
(
#date varchar(20)
)
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT
convert(varchar,Patient_Ref_master.creation_Date,105) as 'creation_Date',
Patient_Ref_master.Sr_No as 'sr_No',
old_new_patient.old_new as 'old_new',
Patient_Ref_master.Pat_ID as 'Pat_ID',
Patient_Master.Pat_FName +' '+Patient_Master.Pat_SName as 'NAME',
Dept_ID as 'Dept_ID',
Dept_Master.Dept_Name as 'Dept_Name',
Doc_Master.Doc_ID as 'Doc_Master',
Doc_Master.Doc_FName+' '+Doc_Master.Doc_SName as 'Doc_Name',
Patient_Master.Pat_Addr as 'addr',
Gender_master.Name1 as 'Pat_Sex',
Patient_Master.Age as 'age'
FROM Patient_Ref_master
left join dbo.old_new_patient on dbo.old_new_patient.code=Patient_Ref_master.old_new
left join dbo.Dept_Master on Dept_Master.Dept_code = Patient_Ref_master.Dept_ID
left join Patient_Master on Patient_Master.Pat_Code=Patient_Ref_master.Pat_ID
left join Doc_Master on Doc_Master.Doc_ID=Patient_Ref_master.Doc_ID
left join Gender_master on Gender_master.Code=Patient_Master.Pat_Sex
where
Patient_Ref_master.creation_Date=#date
--MONTH(Patient_Ref_master.creation_Date)=#month and Dept_ID=#dept
order by Patient_Ref_master.Sr_No asc
I want something like the following. where 1st row has the patient for 2nd aug under Patient_ID_New column because he is new and 2nd line because he is old. I want a blank space like 1st row in Patient_Id_Old coumn
Date No Patient_ID_New Patient ID Old
02-08-2013 11 11
02-08-2013 13 1
Yes, you can use case statemnet for the following:
Select
(Case when "condition for oldpatient" Then PatientName Else Null End) Old_Patient,
(Case when "condition for Newpatient" Then PatientName Else Null End) New_Patient
From TableName
Ah, now I get it. I think this is what you want...
SELECT
convert(varchar,Patient_Ref_master.creation_Date,105) as 'creation_Date',
Patient_Ref_master.Sr_No as 'sr_No',
Case When old_new_patient.old_new = 0x1 Then old_new_patient.old_new
Else Patient_Ref_master.Pat_ID
End as 'Pat_ID',
Patient_Master.Pat_FName +' '+Patient_Master.Pat_SName as 'NAME',
MyTableA has several million records. On regular occasions every row in MyTableA needs to be updated with values from TheirTableA.
Unfortunately I have no control over TheirTableA and there is no field to indicate if anything in TheirTableA has changed so I either just update everything or I update based on comparing every field which could be different (not really feasible as this is a long and wide table).
Unfortunately the transaction log is ballooning doing a straight update so I wanted to chunk it by using UPDATE TOP, however, as I understand it I need some field to determine if the records in MyTableA have been updated yet or not otherwise I'll end up in an infinite loop:
declare #again as bit;
set #again = 1;
while #again = 1
begin
update top (10000) MyTableA
set my.A1 = their.A1, my.A2 = their.A2, my.A3 = their.A3
from MyTableA my
join TheirTableA their on my.Id = their.Id
if ##ROWCOUNT > 0
set #again = 1
else
set #again = 0
end
is the only way this will work if I add in a
where my.A1 <> their.A1 and my.A2 <> their.A2 and my.A3 <> their.A3
this seems like it will be horribly inefficient with many columns to compare
I'm sure I'm missing an obvious alternative?
Assuming both tables are the same structure, you can get a resultset of rows that are different using
SELECT * into #different_rows from MyTable EXCEPT select * from TheirTable and then update from that using whatever key fields are available.
Well, the first, and simplest solution, would obviously be if you could change the schema to include a timestamp for last update - and then only update the rows with a timestamp newer than your last change.
But if that is not possible, another way to go could be to use the HashBytes function, perhaps by concatenating the fields into an xml that you then compare. The caveat here is an 8kb limit (https://connect.microsoft.com/SQLServer/feedback/details/273429/hashbytes-function-should-support-large-data-types) EDIT: Once again, I have stolen code, this time from:
http://sqlblogcasts.com/blogs/tonyrogerson/archive/2009/10/21/detecting-changed-rows-in-a-trigger-using-hashbytes-and-without-eventdata-and-or-s.aspx
His example is:
select batch_id
from (
select distinct batch_id, hash_combined = hashbytes( 'sha1', combined )
from ( select batch_id,
combined =( select batch_id, batch_name, some_parm, some_parm2
from deleted c -- need old values
where c.batch_id = d.batch_id
for xml path( '' ) )
from deleted d
union all
select batch_id,
combined =( select batch_id, batch_name, some_parm, some_parm2
from some_base_table c -- need current values (could use inserted here)
where c.batch_id = d.batch_id
for xml path( '' ) )
from deleted d
) as r
) as c
group by batch_id
having count(*) > 1
A last resort (and my original suggestion) is to try Binary_Checksum? As noted in the comment, this does open the risk for a rather high collision rate.
http://msdn.microsoft.com/en-us/library/ms173784.aspx
I have stolen the following example from lessthandot.com - link to the full SQL (and other cool functions) is below.
--Data Mismatch
SELECT 'Data Mismatch', t1.au_id
FROM( SELECT BINARY_CHECKSUM(*) AS CheckSum1 ,au_id FROM pubs..authors) t1
JOIN(SELECT BINARY_CHECKSUM(*) AS CheckSum2,au_id FROM tempdb..authors2) t2 ON t1.au_id =t2.au_id
WHERE CheckSum1 <> CheckSum2
Example taken from http://wiki.lessthandot.com/index.php/Ten_SQL_Server_Functions_That_You_Have_Ignored_Until_Now
I don't know if this is better than adding where my.A1 <> their.A1 and my.A2 <> their.A2 and my.A3 <> their.A3, but I would definitely give it a try (assuming SQL Server 2005+):
declare #again as bit;
set #again = 1;
declare #idlist table (Id int);
while #again = 1
begin
update top (10000) MyTableA
set my.A1 = their.A1, my.A2 = their.A2, my.A3 = their.A3
output inserted.Id into #idlist (Id)
from MyTableA my
join TheirTableA their on my.Id = their.Id
left join #idlist i on my.Id = i.Id
where i.Id is null
/* alternatively (instead of left join + where):
where not exists (select * from #idlist where Id = my.Id) */
if ##ROWCOUNT > 0
set #again = 1
else
set #again = 0
end
That is, declare a table variable for collecting the IDs of the rows being updated and use that table for looking up (and omitting) IDs that have already been updated.
A slight variation on the method would be to use a local temporary table instead of a table variable. That way you would be able to create an index on the ID lookup table, which might result in better performance.
If schema change is not possible. How about using trigger to save off the Ids that have changed. And only import/export those rows.
Or use trigger to export it immediately.