Needing to access table from subquery in main update query - sql

I'm in need of a way to access a column from the inner table from a subquery, which I have included below with database/table names changed. The inner query returns all of the Item_Ids of Items that have a specific term config and belong to a specific customer. Obviously, the SET currently doesn't work as I can't access any of the rows of let from the main query.
I'm fairly new to SQL and am struggling to wrap my head around how I might convert this to using joins instead of a subquery. The problem is that I need to be able to set ALL of the Grand Totals for any of the Item_Ids that come from the subquery.
UPDATE [Database].[dbo].[Items]
SET GrandTotal = GrandTotal / let.CurrentValue
WHERE Id IN (
SELECT let.Item_Id
FROM [Database].[dbo].[ItemTerms] let
WHERE TermConfig_Id = 'TERM_CONFIG_ID'
AND Item_Id IN (
SELECT le2.Id
FROM [Database].[dbo].[LaneExhibits] le2
WHERE Customer_Id = 'CUST_ID'
)
)
EDIT: Add Sample Row from Subquery
Columns are Id, DataValueStatus, CurrentValue, PreviousValue, Item_Id, TermConfig_Id. The subquery only returns the Item_Id but that is the rest of the data.
424C8BF4-0FCB-E711-80C9-005056BA0972 1 460 NULL 2D4C8BF4-0FCB-E711-80C9-005056BA0972 B8FCE730-27BE-E711-80C9-005056BA0972

The inner join version:
UPDATE i
SET GrandTotal = GrandTotal / let.CurrentValue
FROM [Database].[dbo].[Items] i
INNER JOIN [Database].[dbo].[ItemTerms] let ON i.Id=let.Item_Id
WHERE TermConfig_Id = 'TERM_CONFIG_ID'
AND Item_Id IN (
SELECT le2.Id
FROM [Database].[dbo].[LaneExhibits] le2
WHERE Customer_Id = 'CUST_ID'
)

Merge is your friend https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql?view=sql-server-2017
simplified sample from your example
MERGE [Database].[dbo].[Items] AS target
USING (SELECT let.Item_Id, let.CurrentValue FROM [Database].[dbo].[ItemTerms] let
/* other joins and filters here */
) AS source (Item_Id, CurrentValue)
ON (target.Item_Id = source.id /* or what you want */)
WHEN MATCHED THEN
UPDATE SET GrandTotal = source.GrandTotal / source.CurrentValue

Related

SQL aggregation updates for some but not others

I am running this query which should take the sum of an amount from a table and if it <= 0, update the status of a different table from Active to Deactive. The query updates some values but not others. I have isolated to one observation where there are 3 payments that total 0 where it does not work.(123456789) What could be happening here? I am using sql query in Microsoft Access. Thank you.
UPDATE tbl_MASTER INNER JOIN tbl_Payments ON tbl_MASTER.DeviceID = tbl_Payments.DeviceID SET tbl_MASTER.ActiveDeactive = "DeActive"
WHERE tbl_Payments.Amount=(SELECT SUM(tbl_Payments.Amount) <= 0 FROM tbl_Payments) AND tbl__MASTER = '123456789';
Your query doesn't really make a lot of sense, to be honest. Where you have tbl_Payments.Amount=(SELECT SUM(tbl_Payments.Amount) <= 0 FROM tbl_Payments), that sub-query will just be summing up the "Amount" of every record in the table, regardless of which DeviceID. Plus, you're looking for one record in tbl_Payments table where the Amount = the sum of all of the Amounts in tbl_Payments??
I'd suggest that your query probably needs to be something more like this:
UPDATE tbl_MASTER SET tbl_MASTER.ActiveDeactive = "DeActive"
WHERE (SELECT SUM(tbl_Payments.Amount) FROM tbl_Payments WHERE tbl_Payments.DeviceID = tbl_MASTER.DeviceID) <= 0 AND tbl__MASTER = '123456789';
Currently, the subquery does not correlate specific IDs to outer query and also you specify <= 0 inside subquery's SELECT clause. Consider adjusting for IN clause with logic in a conditional HAVING and use table aliases to distinguish same named tables.
UPDATE tbl_MASTER AS m
INNER JOIN tbl_Payments AS p
ON m.DeviceID = p.DeviceID
SET m.ActiveDeactive = 'DeActive'
WHERE sub_p.DeviceID IN (
SELECT sub_p.DevideID
FROM tbl_Payments AS sub_p
GROUP BY sub_p.DeviceID
HAVING SUM(sub_p.Amount) <= 0
)

Problems shortening a SQL query

I am trying to make a query that works with a temp table, work without that temp table
I tried doing a join in the subquery without the temp table but I don't get the same results as the query with the temp table.
This is the query with the temp table that works as I want:
create table #results(
RowId id_t,
LastUpdatedAt date_T
)
insert into #results
select H.RowId, H.LastUpdatedAt from MemberCarrierMap M Join MemberCarrierMapHistory H on M.RowId = H.RowId
update MemberCarrierMap
set CreatedAt = (select MIN(LastUpdatedAt) from #results r where r.rowId = MemberCarrierMap.rowId)
Where CreatedAt is null;
and here is the query I tried without the temp table that doesn't work like the above:
update MemberCarrierMap
set CreatedAt = (select MIN(MH.LastUpdatedAt) from MemberCarrierMapHistory MH join MemberCarrierMap M on MH.RowId = M.RowId where MH.RowId = M.RowId )
Where CreatedAt is null;
I was expecting the 2nd query to work as the first but It is not. Any suggestions on how to achieve what the first query does without the temp table?
This should work:
update M
set M.CreatedAt = (select MIN(MH.LastUpdatedAt) from MemberCarrierMapHistory MH WHERE MH.RowId = M.RowId)
FROM MemberCarrierMap M
Where M.CreatedAt is null;
Your question is more or less a duplicate of this answer. There, you will find multiple solutions. But the ones that implement correlated subqueires are less performant than the one that simply uses an uncorrelated aggregation subquery inside a join.
Applying it to your situation, you will have this:
update m
set m.createdDate = hAgg.maxVal
from memberCarrierMap m
join (
select rowId, max(lastUpdatedAt) as maxVal
from memberCarrierMapHistory
group by rowId
) as hAgg
on m.rowId = hAgg.rowId
where m.createdAt is null;
Basically, it's more performant because it is more expensive to run aggregations and filterings on a row-by-row basis (which is what happens in a correlated subquery) than to just get the aggregations out of the way all at once (joins tend to happen early in processing) and perform the match afterwards.

Run the Update Statement from another Select in SQL query

I am trying to create an update query that will update my table values based on pallet number match.
SELECT [pallet] [quantity]
FROM dba.Inventory
This will returns 2 columns, one with pallet and the other with count.
I need to put this in a update statement that will match each pallet between here and table TABLE1 and update the counts in TABLE1
Use Common Table Expression.
Syntax goes like
with CTE_Values()
AS
( --- Your Statement---)
Update T
Set Col = C.col
From Table T Join CTE_Values C
On .....
I think that one easy solution (without evaluating the SELECT itself that looks quite convoluted) is to put the whole SELECT into a CTE and use it as source for your update. Something like this:
;WITH SrcCte AS (
SELECT pallet, SUM(total) as quantity
FROM (
SELECT r1.pallet, total
FROM
(SELECT plet_nbr, COUNT(serl_nbr) as total FROM Inventory group by plet_nbr )c1
right join
(select pallet from dbo.RFS where status NOT LIKE 'Not Available')r1
on r1.pallet = c1.plet_nbr
UNION all
Select r2.pallet, sum(iloc_qty) as total
FROM
(SELECT plet_nbr, iloc_qty FROM Inventory WHERE([matl_nbr] Like '#%')) c2
right join
(select pallet from dbo.RFS where status NOT LIKE 'Not Available') r2
on r2.pallet = c2.plet_nbr
where iloc_qty is not null
GROUP BY r2.pallet
)
AS final
GROUP BY pallet
)
UPDATE Dest
SET Dest.Cnt = Src.Quantity
FROM Table1 AS Dest
JOIN SrcCte AS Src ON Src.pallet = Dest.pallet

SQL Server 2014 Replace Distinct? DeIdentify Data

I am going to explain again what I am trying to do in hopes that you can help.
Table 1 has 4061 rows with columns that include
[Name],[Address1],[Address2],[Address3],[City],[State],[Zip],[Country],[Phone]
and 20 other columns. Table 1 is data that needs to be deidentified. Table 1 has 1534 distinct [Name] rows out of 4061 rows total.
Table 2 has auto generated data which includes the same columns. I would like to replace the above mentioned columns in table 1 with data from table 2. I want to select distinct based on [Name] from table one and then [Name],[Address1],[Address2],[Address3],[City],[State],[Zip],[Country],[Phone] with a new set of distinct data from table 2.
I do not want to just update each row with a new address as that will screw up the data consistency. By replacing only distinct this will allow me to preserve the data consistency while changing the row data in table 1. When I am done I would like to have 1534 distinct new de-identified [Name] [Address1],[Address2],[Address3],[City],[State],[Zip],[Country],[Phone] in table 1 from table 2.
You would use join in the update. You can generate a join key for 1500 rows using row_number():
update toupdate
set t.address = f.address
from (select t.*, row_number() over (order by newid()) as seqnum
from table t
) toupdate join
(select f.*, row_number() over (order by newid()) as seqnum
fake f
) f
on toupdate.seqnum = f.seqnum and t.seqnum <= 1500;
Here is how I ended up doing it.
First I ran a statement to select distinct and inserted it into a table.
Select Distinct [Name],[Address1],[City],[State],[Zip],[Country],[Phone]
INTO APMAST2
FROM APMAST
I then added name2 column in APMAST2 and used a statement to create a sequential id field into APMAST2.
DECLARE #id INT
SET #id = 0
UPDATE APMAST2
SET #id = id = #id + 1
GO
Now I have my distinct info plus a blank name field and a sequential ID field in APMAST2. Now I can join this date with my fakenames table which I generated from. HERE using their bulk tool.
Using a Join Statement I joined my fake data with APMAST2
Update dbo.APMAST2
SET dbo.APMAST2.Name = dbo.fakenames.company,
dbo.APMAST2.Address1 = dbo.fakenames.streetaddress,
dbo.APMAST2.City = dbo.fakenames.City,
dbo.APMAST2.State = dbo.fakenames.State,
dbo.APMAST2.Zip = dbo.fakenames.zipcode,
dbo.APMAST2.Country = dbo.fakenames.countryfull,
dbo.APMAST2.Phone = dbo.fakenames.telephonenumber
FROM
dbo.APMAST2
INNER JOIN
dbo.fakenames
ON dbo.fakenames.number = dbo.APMAST2.id
Now I have my fake data loaded but I kept my original Name field so I could reload this data into my full table ARMAST so now I can do a join between ARMAST2 and ARMAST.
Update dbo.APMAST
SET dbo.APMAST.Name = dbo.APMAST2.Name,
dbo.APMAST.Address1 = dbo.APMAST2.Address1,
dbo.APMAST.City = dbo.APMAST2.City,
dbo.APMAST.State = dbo.APMAST2.State,
dbo.APMAST.Zip = dbo.APMAST2.Zip,
dbo.APMAST.Country = dbo.APMAST2.Country,
dbo.APMAST.Phone = dbo.APMAST2.Phone
FROM
dbo.APMAST
INNER JOIN
dbo.apmast2
ON dbo.apmast.name = dbo.APMAST2.name2
Now my original table has all fake data in it but it keeps the integrity it had , well most of it, so the data looks good when reported on but is de-identified. You can now remove APMAST2 or keep it if you need to match this with other data later on. I know this is long and I am sure there is a better way to do it but this is how I did it, suggestions welcome.

How to increment a column based on two tables that are joined

I am trying to increment a column on a sql server table based on the join between the initial table and the joined table. The idea is to update tblForm10Objectives, set the ObjectiveNumber column to an increment number starting with 1 based on the number of rows returned from the join of tblForm10GoalsObjectives and tblForm10Objectives where ID_Form10Goal equals a number. Example query so far:
Update tblForm10Objectives
Set ObjectiveNumber = rn
From (
Select ROW_NUMBER() over (PARTITION by OG.ID_Form10Goal) as rn
, *
From (
Select *
From tblForm10GoalsObjectives OG
Join tblForm10Objectives O On OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
Order by O.ID_Form10Objective
) as tblForm10Objectives;
If the select portion of the query is performed the columns are displayed so you can see the ObjectiveNumber is currently 0 where ID_Form10Goal = 4
Once the update runs I need for the ObjectiveNumber to show 1 , 2; since there are two rows for ID_Form10Goal = 4.
I had to introduce a new table to the logic of this update statement, the table name is tblForm10Goals. The objectives need to be pulled by ID_Agency instead of ID_Form10Goal I am getting an error message stating a "a multipart identifier 'dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective' could not be bound. I am using the following SQL Update statement:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM tblForm10Goals As g
Left Join tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
Right Join
(
SELECT
ROW_NUMBER() OVER (PARTITION BY g.ID_Agency
ORDER BY OB.ID_Form10Objective) AS rn,
OB.ID_Form10Objective
FROM tblForm10Goals g
LEFT JOIN dbo.tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
RIGHT JOIN dbo.tblForm10Objectives OB ON gobs.ID_Form10Objective = OB.ID_Form10Objective
Where g.ID_Agency = 2
) rns ON dbo.tblForm10Objectives.ID_Form10Object = rns.ID_Form10Objective
Your example seems to be missing a closing parenthesis somewhere, and without the table structures to look at, I can't be certain of my answer. It seems you have two tables:
tblForm10Objectives
-------------------
ID_Form10Objective
ObjectiveNumber
...
and
tblForm10GoalsObjectives
------------------------
ID_Form10Goal
ID_Form10Objective
...
If this is the case, the following query should give you the results you desire:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM dbo.tblForm10Objectives INNER JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY OG.ID_Form10Goal
ORDER BY O.ID_Form10Objective) AS rn,
O.ID_Form10Objective
FROM dbo.tblForm10Objectives O INNER JOIN
dbo.tblForm10GoalsObjectives OG ON OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
) rns ON dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective
If you run the inner SELECT statement, you will see the desired ObjectiveNumber values and the corresponding ID_Form10Objective that will get updated with those values.
If you post your table structures, I or someone else may be able to be of more help.