Update query with Join SQL Server - sql-server

I have these two tables
The first image represents ObjectData Table, and the second ColumnsSet Table.
In ObjectData the ColID attribute represents the foreign key of ColumnID in ColumnsSet Table.
I want to update a cell in Data attribute of ObjectData for example number 10 to be 20.
query :
UPDATE ObjectData SET ObjectData.Data = 'Ahmed'
FROM ColumnsSet
INNER JOIN ObjectData ON ColumnsSet.ColumnID = ObjectData.ColID
WHERE ObjectData.ColID = ColumnsSet.ColumnID
What is the correct SQL statement?

UPDATE a SET a.Data = 'Ahmed'
FROM ObjectData a
INNER JOIN ColumnsSet ON ColumnsSet.ColumnID = a.ColID
when you are using inner join it selects data which returns join condition true and not null datas
there is no need to this 'where ....'
but you have to be sure which data will update
at first use this code and select all data
SELECT *
FROM ObjectData a
INNER JOIN ColumnsSet ON ColumnsSet.ColumnID = a.ColID
and then write where clause
then change it to update

Let me show on example how to update.
At first, we should create tables:
CREATE TABLE ObjectData
(
ID INT,
CollID INT,
Data VARCHAR(50)
)
CREATE TABLE ColumnSet
(
ColumnID INT,
ColumnName VARCHAR(50)
)
Then insert data:
INSERT INTO ObjectData
(
ID,
CollID,
Data
)
VALUES
( 113, -- ID - int
1, -- CollID - int
'1' -- Data - varchar(50)
)
, (114, 5, '')
, (115, 10015, 'Mohamed')
, (116, 20026, 'Abdulghani')
INSERT INTO ColumnSet
(
ColumnID,
ColumnName
)
VALUES
( 1, -- ColumnID - int
'ID' -- ColumnName - varchar(50)
)
, (5, 'EmployeeID')
, (10015, 'FirsName')
And the final step is updating where you should write what rows need to be updated by WHERE operator:
UPDATE od
SET od.Data = 'Hey!'
FROM ObjectData od
INNER JOIN ColumnSet cs ON cs.ColumnID =od.CollID
--WHERE OD.DATA IN ('1', '10')
WHERE OD.CollID IN (1, 5)
You can write in WHERE statement any condition to choose your row which will be updated.
--Check our update statements:
SELECT
*
FROM ObjectData od
INNER JOIN #ColumnSet cs ON cs.ColumnID =od.CollID
WHERE OD.DATA IN ('1', '10')

Related

How to insert column from another table when inserting it from userdefined datatable?

CREATE PROC [dbo].[usp_InsertBulkShipmentData]
(
#RetVal VARCHAR(1000) OUTPUT,
#ship dbo.ShipmentData READONLY
)
AS
DECLARE #ShipmentID BIGINT
Declare #Output table (id int)
BEGIN
INSERT INTO
dbo.Shipment (ShipmentType,scaccode,ShipmentControl,countryLoading,PortLoading,ShipperName,ShipperAddressOne,ShipperCity,ShipperCountry,ShipperProvince,
ShipperZip,ShipperPhone,ShipperEmail,ConsigneeName,ConsigneeAddressOne,ConsigneeCity,ConsigneeCountry,ConsigneeState,ConsigneeZip,
ConsigneePhone,ConsigneeEmail,ResponseCode,astrayExportDate,bondType,bondDestPort,bondOnwardscac,bondCarrierIRS,
bondNumber,bondTransferIRS,bondForeignPort,bondDepartureDate,MexiPediNumber)
OUTPUT Inserted.id into #Output
SELECT sh.DDcode,s.SCACCode,s.ShipmentControl,s.CountryLoading,s.ProvinceLoading,s.ShipperName,s.ShipperAddress,s.ShipperCity,s.ShipperCountry,s.ShipperProvince,
s.ShipperZip,s.ShipperPhone,s.ShipperEmail,s.ConsigneeName,s.ConsigneeAddressOne,s.ConsigneeCity,s.ConsigneeCountry,s.ConsigneeState,s.ConsigneeZip,
s.ConsigneePhone,s.ConsigneeEmail,s.CustomControl,s.DateShipmentLeft,s.InbondEntryType,s.InbondDestination,s.OnwardCarrier,s.BondCarrier,
s.Inbond,s.bondTransfer,s.ForeignPortDestination,s.EstimatedDeparture,s.MexiPediNumber
FROM #ship s INNER JOIN ShipmentTypeDropDown sh on sh.DisplayName=s.ShipmentType
select id from #Output
SET #RetVal = 'true|Record Inserted Successfully|'
END
BEGIN
SELECT #ShipmentID=id;
INSERT INTO dbo.Ship_commodity([Description],Quantity,manifestUnitCode,
[weight],weightUnitCode,countryCode,customsShipmentValue,commodityCode,MarksNumbers)
SELECT sp.CommoditiesDescription,sp.Quantity,qu.DDCode,sp.
[Weight],wu.DDCode,sp.CountryOrigin,sp.Value,sp.HarmonizedCode,sp.MarksNumbers
FROM #ship sp INNER JOIN WeightUnitDropDown wu on wu.DisplayName=sp.WeightUnitCode
INNER JOIN QuantityUnitDropDown qu on qu.DisplayName=sp.QuantityUnit
END
id is autogenerated in Shipment table. I wan to insert this id into Ship_commodity where ShipmentID=id.
I am inserting the records from user defined datatable, for every record , id is generated in Shipment table. When inserting into
Ship_commodity table i want to insert the Shipment id for every record , where ShipmentID=id.
How should i achieve this? please suggest.
In your first insert, you need to get the primary key of #ship to be able to join the output table to it (make sure to add extra columns to #output):
OUTPUT inserted.id, inserted.scaccode, inserted.ShipmentControl into #Output
Then you can join #output to #ship (i'm assuming Ship_commodity has a column fkShipmentId):
INSERT INTO dbo.Ship_commodity
(fkShipmentId, [Description], Quantity, manifestUnitCode, [weight], weightUnitCode,
countryCode, customsShipmentValue, commodityCode, MarksNumbers)
SELECT
i.id,
sp.CommoditiesDescription,
sp.Quantity,
qu.DDCode,
sp.[Weight],
wu.DDCode,
sp.CountryOrigin,
sp.Value,
sp.HarmonizedCode,
sp.MarksNumbers
FROM #ship sp
INNER JOIN WeightUnitDropDown wu on wu.DisplayName=sp.WeightUnitCode
INNER JOIN QuantityUnitDropDown qu on qu.DisplayName=sp.QuantityUnit
INNER JOIN #output i ON i.scaccode = sp.scaccode AND i.ShipmentControl = sp.ShipmentControl;

Cursor on a trigger

I'm using SQL Server 2008.
I have an after trigger for INSERT, UPDATE and DELETE action defined in the table. My problem is that currently my trigger inserts one record at a time and I need multiple records as for one
SELECT TOP 1 #ParentID FROM ... WHERE ID = #ID
returns multiple unique records.
(See this comment below "-- this subquery returns more than 1 value, so I need to insert in the search Audit table as many ParentIDs as it returns")
I believe I need to use cursor, but I'm not sure where exactly to declare and open cursor.
--CREATE PROCEDURE [dbo].[SP_Auditing]
-- #ID INT, #Code VARCHAR(3), #AuditType VARCHAR(10), #ParentCode VARCHAR(3) = NULL, #ParentID INT = NULL
--AS
--BEGIN
-- INSERT INTO myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
-- VALUES(#ID, #Code, #AuditType, #ParentCode, #ParentID)
--END
GO
CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL] ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE NOT FOR REPLICATION
AS
BEGIN
DECLARE #ID INT, #Code VARCHAR(3), #AuditType VARCHAR(10), #ParentCode VARCHAR(3), #ParentID INT SET #Code = 'DOC'
IF EXISTS (SELECT 1 FROM inserted) AND
NOT EXISTS (SELECT 1 FROM deleted)
BEGIN
SELECT TOP 1
#ID = ins.ID,
#ParentID = (
SELECT TOP 1 CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT)
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)
ON t.Id = v.ID
WHERE v.ID = #ID --284
), **-- this subquery returns more than 1 value, so I need to insert in the search Audit table as many ParentIDs as it returns**
#AuditType = 'INSERT' FROM inserted ins
IF #ID IS NOT NULL
AND
#ParentID IS NOT NULL
AND
#ParentCode IS NOT NULL
EXEC [MyDB].[dbo].SP_Auditing] #ID, #Code, #AuditType, #ParentCode, #ParentID
END
-- below is the same logic for UPDATE and DELETE actions...
The stored procedure above simply inserts data into the Audit table.
Never use scalar variables in triggers because insert, update, and delete may affect multiple rows. As to your trigger, try something like this.
CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]
ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE
NOT FOR REPLICATION
AS
BEGIN
;with act as (
select isnull(i.id,d.id) id, --either deleted or inserted is not null
case when i.id is not null and d.id is not null then 'update'
when i.id is not null then 'insert'
else 'delete' end auditType
from inserted i full outer join deleted d on i.id = d.id
),
audit_cte as (
SELECT act.id, 'DOC' Code,
CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) parentid,
act.auditType, 'parentcode' parentCode
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK) ON t.Id = v.ID
inner join act on act.id = t.id
)
insert myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
select id,code,AuditType, ParentCode, ParentID
from audit_cte
where parentCode is not null and parentid is not null
end
Why do you need to get the records one by one? From my understanding you want to keep the log.
IF EXISTS (SELECT 1 FROM inserted) AND
NOT EXISTS (SELECT 1 FROM deleted)
BEGIN
INSERT INTO [Your_Log_Table]
SELECT
ins.ID, [Code],'INSERT',[PrentCode],
(SELECT TOP 1 CAST(RIGHT(parentId,LEN(parentId) -
LEN(LEFT(parentId,3))) AS INT)
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)
ON t.Id = v.ID
WHERE v.ID = ins.ID --284
)
FROM inserted ins
END
See Alex Kudryashev's answer. I needed to tweak a little his logic to sort out duplicate records with the same ParentIDs for the insertion into the Audit table. I added one more cte just below Alex's cte_Audit as follows
CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]
ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE
NOT FOR REPLICATION
AS
BEGIN
;with act as (
select isnull(i.id,d.id) id, --either deleted or inserted is not null
case when i.id is not null and d.id is not null then 'update'
when i.id is not null then 'insert'
else 'delete' end auditType
from inserted i full outer join deleted d on i.id = d.id
),
audit_cte as (
SELECT act.id, 'DOC' Code,
CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) parentid,
act.auditType, 'parentcode' parentCode
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK) ON t.Id = v.ID
inner join act on act.id = t.id
)
insert myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
select id,code,AuditType, ParentCode, ParentID
from audit_cte
where parentCode is not null and parentid is not null
,CTE_dupsCleanup AS (
SELECT DISTINCT
Code,
Id,
AuditType,
ParentCode,
ParentId,
-- ROW_NUMBER() OVER(PARTITION BY ParentId, ParentCode, AuditType ORDER BY ParentId) AS Rn
FROM AUDIT_CTE
WHERE ParentCode IS NOT NULL
AND ParentId IS NOT NULL )
Then using Rn = 1 inserted only unique records into the Auidt table. Like this:
INSERT [ISSearch].[dbo].[SearchAudit] (Code, ID, AuditType, ParentCode, ParentID)
SELECT
Code,
ID,
AuditType,
ParentCode,
ParentId
FROM CTE_dupsCleanup
-- WHERE Rn = 1
END

Avoid referring table two times in the WHERE clause

Following is a simplified version of my database in SQL Server 2005. I need to select employees based on business units. Each employee has home department, parent department and visiting department. Based on the department, business unit can be found out.
For an employee, if the HomeDeptID = ParentDeptID, then
#SearchBusinessUnitCD should be present for the VisitingDeptID.
If HomeDeptID <> ParentDeptID, then #SearchBusinessUnitCD should be
present for the ParentDeptID.
Following query works fine. But it has scan on the #DepartmentBusinesses table two times. Is there a way to use the table #DepartmentBusinesses only once by making it as a CASE statement or similar?
DECLARE #SearchBusinessUnitCD CHAR(3)
SET #SearchBusinessUnitCD = 'B'
--IF HomeDeptID = ParentDeptID, then #SearchBusinessUnitCD should be present for the VisitingDeptID
--IF HomeDeptID <> ParentDeptID, then #SearchBusinessUnitCD should be present for the ParentDeptID
CREATE TABLE #DepartmentBusinesses (DeptID INT, BusinessUnitCD CHAR(3))
INSERT INTO #DepartmentBusinesses
SELECT 1, 'A' UNION ALL
SELECT 2, 'B'
CREATE NONCLUSTERED INDEX IX_DepartmentBusinesses_DeptIDBusinessUnitCD ON #DepartmentBusinesses (DeptID,BusinessUnitCD)
DECLARE #Employees TABLE (EmpID INT, HomeDeptID INT, ParentDeptID INT, VisitingDeptID INT)
INSERT INTO #Employees
SELECT 1, 1, 1, 2 UNION ALL
SELECT 2, 2, 1, 3
SELECT *
FROM #Employees
WHERE
(
HomeDeptID = ParentDeptID
AND
EXISTS (
SELECT 1
FROM #DepartmentBusinesses
WHERE DeptID = VisitingDeptID
AND BusinessUnitCD = #SearchBusinessUnitCD)
)
OR
(
HomeDeptID <> ParentDeptID
AND
EXISTS (
SELECT 1
FROM #DepartmentBusinesses
WHERE DeptID = ParentDeptID
AND BusinessUnitCD = #SearchBusinessUnitCD
)
)
DROP TABLE #DepartmentBusinesses
Plan
SELECT *
FROM #Employees e
WHERE EXISTS (
SELECT 1
FROM #DepartmentBusinesses t
WHERE t.BusinessUnitCD = #SearchBusinessUnitCD
AND (
(e.HomeDeptID = e.ParentDeptID AND t.DeptID = e.VisitingDeptID)
OR
(e.HomeDeptID != e.ParentDeptID AND t.DeptID = e.ParentDeptID)
)
)
You can give this a try:
SELECT e.*
FROM #Employees AS e
INNER JOIN #DepartmentBusinesses AS d
ON (d.DeptID = e.VisitingDeptID AND e.HomeDeptID = e.ParentDeptID) OR
(d.DeptID = e.ParentDeptID AND e.HomeDeptID <> e.ParentDeptID)
WHERE d.BusinessUnitCD = #SearchBusinessUnitCD

String Replace column data with data from another table

I have two tables:
TableA:
ID Values
---------------
1 Q
2 B
3 TA
4 BS
TableB:
RawValue Value
------------------
[1][4] QBS
[2][1][3] BQTA
I need to generate TableB values with its given RawValues. each [X] in rawvalue is the ID coulmn of TableA and shoud be replace with its value .
[1][4] means that Value of TableA with has ID of 1 (Q) and Value of TableA with has ID of 4 (BS) then should equal to QBS.
can anyone suggest a way to do it?
this is what I have already tried:
update tableb set value=replace(rawvalue,'[' + (select id from tablea where id = cast(replace(replace(rawdata,'[',''),']','') as int)) + ']',
(select values from tablea where id = cast(replace(replace(rawdata,'[',''),']','') as int)))
By the way: this is still in test process and I can totally change tables, rowvalue format and replacement methods if anyone has a better idea.
declare #tableA table (id int, value varchar(50))
insert into #tableA (id, value)
select 1, 'Q' union all
select 2, 'B' union all
select 3, 'TA' union all
select 4, 'BS'
declare #tableB table (rawdata varchar(255), value varchar(255))
insert into #tableB (rawdata)
select '[1][4]' union all -- QBS
select '[2][1][3]' -- BQTA
update b
set value = (
select a.value + ''
from #tableA a
cross apply (select charindex ('[' + cast (a.id as varchar(50)) + ']', b.rawdata) as pos) p
where pos > 0
order by pos
for xml path('')
)
from #tableB b
select * from #tableB
P.S. I would recommend not to name field similar to reserved keywords (I mean Values).
Turn RawValue into XML, shred the XML to get one row for each value in RawValue and join to TableA to get the value.
Use the for xml path() trick to concatenate the values from TableA.
update TableB
set Value = (
select T.Value as '*'
from (
select row_number() over(order by T2.X) as SortOrder,
TableA.Value
from (select cast(replace(replace(TableB.RawValue, '[', '<x>'), ']', '</x>') as xml)) as T1(X)
cross apply T1.X.nodes('x') as T2(X)
inner join TableA
on TableA.ID = T2.X.value('text()[1]', 'int')
) as T
order by T.SortOrder
for xml path('')
)
SQL Fiddle

SQL how to get an equality comparator on a list of ints

I'm writing an SQL query as follows:
ALTER proc [dbo].[Invoice_GetHomePageInvoices] (
#AreaIdList varchar(max)
, #FinancialYearStartDate datetime = null
, #FinancialYearEndDate datetime = null
) as
set nocount on
select *
from Invoice i
left outer join Organisation o on i.OrganisationId = o.Id
left outer join Area a on i.AreaId = a.Id
where i.InvoiceDate BETWEEN #FinancialYearStartDate AND #FinancialYearEndDate
The #AreaIdList parameter is going to be in the format "1,2,3" etc.
I'm wanting to add a line which will only return invoices who have area id equal to any of the ids in #AreaIdList.
I know how to do a statement if it was on areaId to search on ie. where i.AreaId == areaId problem is now I have this list I got to compare for every area Id in #AreaIdList.
Can anybody tell me how you would go about this?
Unpack your ID list to a table and use where AreadID in (select ID from ...)
ALTER proc [dbo].[Invoice_GetHomePageInvoices] (
#AreaIdList varchar(max)
, #FinancialYearStartDate datetime = null
, #FinancialYearEndDate datetime = null
) as
set nocount on
set #AreaIdList = #AreaIdList+','
declare #T table(ID int primary key)
while len(#AreaIdList) > 1
begin
insert into #T(ID) values (left(#AreaIdList, charindex(',', #AreaIdList)-1))
set #AreaIdList = stuff(#AreaIdList, 1, charindex(',', #AreaIdList), '')
end
select *
from Invoice i
left outer join Organisation o on i.OrganisationId = o.Id
left outer join Area a on i.AreaId = a.Id
where i.InvoiceDate BETWEEN #FinancialYearStartDate AND #FinancialYearEndDate and
i.AreadID in (select ID from #T)

Resources