SQL Server - Code for Updating values using inner query self join - sql

this may be quite basic for most, but I'd like to get some help.
Using SQL Server I have the following Orders table (Excel excerpt to simplify):
Please note there are multiple orders (OrderID). Some may have "PrimaryOrder" value, meaning they are related to an existing prior order. Related orders receive the "PrimaryOrder" of the 1st related order, and an "OrderIndex" noting the order they came in.
Only the first order in each set has value. If an order's "PrimaryOrder" is NULL, it means it is a single order and I should simply ignore it.
What I need is, using SQL Server Update command give all orders which are related, the same "value" as their 1st related order's "Value".
Meaning for each order that has "OrderIndex" > 1, update it's Value field from NULL to it's "PrimaryOrder" value.
If "PrimaryOrder" = 1 OR is NULL, ignore and don't update.
Tried some simple INNER JOIN but got lost.
I don't think it should be too complicated, but I might be overthinking it.
Thank you!

You can use correlated sub-query with update statement :
update o
set o.value = (select top (1) o1.value
from Orders o1
where o1.primaryorder = o.primaryorder and
o1.value is not null and
o1.orderindex <= o.orderindex
order by o1.orderindex desc
)
from Orders o
where o.value is null;

Perhaps something like this:
UPDATE #table
SET a.Value=b.Value
FROM #table a INNER JOIN #table b
on a.OrderID=b.PrimaryOrder and a.OrderIndex>1 and a.Value is NULL

UPDATE o
SET Value=MaxVals.MaxValue
FROM Orders o
INNER JOIN (
SELECT MAX(Value) AS MaxValue, PrimaryOrder
FROM Orders
WHERE PrimaryOrder IS NOT NULL
GROUP BY PrimaryOrder
) AS MaxVals ON MaxVals.PrimaryOrder=o.PrimaryOrder
WHERE o.Value IS NULL

Thank you all.
Managed to take something from all the above and this solved it:
UPDATE O
SET O.[Value] = B.[Value]
FROM Orders O INNER JOIN Orders B
ON O.PrimaryOrder = B.[PrimaryOrder] and O.OrderIndex > 1 and O.[Value] is NULL
AND B.[OrderIndex] = 1

Related

SQL query is loading for long period, how it could be optimized?

This is the query:
SELECT
[Code]
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY [OrderNo], [ProductNo] ORDER BY [Quantity] DESC) AS [RowNumber],
SUBSTRING(P.[ProductNo], 1, 2) AS [Code]
FROM [LESMESPRD].[FlexNet_prd].[dbo].[ORDER_DETAIL] AS OD
INNER JOIN [LESMESPRD].[FlexNet_prd].[dbo].[WIP_COMPONENT] AS WC ON [WC].[WiporderNo] = OD.[OrderNo]
AND WC.[WipOrderType] = OD.[OrderType]
AND WC.[Active] = 1
INNER JOIN [LESMESPRD].[FlexNet_prd].[dbo].[COMPONENT] AS C ON C.[ID] = WC.[ComponentID]
INNER JOIN [LESMESPRD].[FlexNet_prd].[dbo].[PRODUCT] AS P ON P.[ID] = C.[ProductID]
WHERE SUBSTRING(P.[ProductNo], 1, 2) IN ('43', '72')
) AS OrderBrandComponents
WHERE [RowNumber] = 1
Executing time is 1 minute and 16 seconds, maybe you can help me optimize it somehow? This query is just small piece of the code, but I found that exactly this part is slowing the process.
I tried to think that maybe problem is in sub select when I try to get my rownumber, from these tables that are linked servers data is executing in seconds, I think problem is with the functions. I hope that this query could be optimized.
I believe the delay is because your query is not sargable based on the SUBSTRING( P.[ProductNo], 1,2 ). The engine can not utilize an index on a function call. But by using the full column and using LIKE based on the first 2 characters Plus wild-card anything after, you get the same records, but able to use an index.
Now, because you are looking for 2 specific product type codes (43 and 72), I reversed the query to START with that table, then find orders the products were used. This may help optimize speed, especially if you have 100 orders with these products, but 1000s of orders otherwise. Thus, starting with a smaller set to begin with.
Also, you dont need all the square brackets all over. Typically, those are only used if you have a column name based on a "reserved" keyword, such as naming a column "from" which is an obvious keyword in a SQL statement. Or things that are known data types, function names, etc.
Finally indexes to help optimize this. I would ensure you have indexes on the following tables
table index
Product ( ProductNo, Id ) -- specifically this order
Component ( ProductID, Id
WIP_COMPONENT ( ComponentId, Active, WipOrderNo, WipOrderType )
ORDER_DETAIL ( OrderNo, OrderType )
SELECT
Code
FROM
(SELECT
ROW_NUMBER() OVER
(PARTITION BY OrderNo, ProductNo
ORDER BY Quantity DESC) AS RowNumber,
SUBSTRING(P.ProductNo, 1, 2) Code
FROM
LESMESPRD.FlexNet_prd.dbo.PRODUCT P
JOIN LESMESPRD.FlexNet_prd.dbo.COMPONENT C
ON P.ID = C.ProductID
JOIN LESMESPRD.FlexNet_prd.dbo.WIP_COMPONENT WC
ON C.ID = WC.ComponentID
AND WC.Active = 1
JOIN LESMESPRD.FlexNet_prd.dbo.ORDER_DETAIL OD
ON WC.WiporderNo = OD.OrderNo
AND WC.WipOrderType = OD.OrderType
WHERE
P.ProductNo like '43%'
OR P.ProductNo like '72%' ) AS OrderBrandComponents
WHERE
OrderBrandComponents.RowNumber = 1

Display Y/N column if record found in detail table

I'm trying to create a query so that I can have a column show Y/N if a particular item was ordered for a group of orders. The item I'm looking for would be OLI.id = '538'.
So my results would be:
Order#, Customer#, FreightPaid
12345, 00112233, Y
12346, 00112233, N
I cannot figure out if I need to use a subquery or the where exists function ?
Here's my current query:
SELECT distinct
OrderID,
Accountuid as Customerno
FROM [SMILEWEB_live].[dbo].[OrderLog] OL
inner join Orderlog_item OLI on OLI.orderlogkey = OL.[key]
inner join Account A on A.uid = OL.Accountuid
where A.GroupId = 'X9955'
and OL.CreateDate >= GETDATE() - 60
I would suggest an exists clause instead of a join:
select ol.OrderID, ol.Accountuid as Customerno,
(case when exists (select 1
from Orderlog_item OLI join
Account A
on A.uid = OL.Accountuid
where OLI.orderlogkey = OL.[key] and A.GroupId = 'X9955'
)
then 1 else 0
end) as flag
from [SMILEWEB_live].[dbo].[OrderLog] OL
where OL.CreateDate >= GETDATE() - 60;
This prevents a couple of problems. First, duplicate rows which are caused when there are multiple matching rows (and select distinct add unnecessary overhead). Second, missing rows, which happen when you use inner join instead of an outer join.

need to replace subquery with JOIN

I need to use join in below instead of Subquery.
can anybody help me to rewrite this with JOIN.
update Table1
set status = 'Edited'
where val_74 ='1' and status ='Valid'
and val_35 is not null
and (val_35,network_id) in
(select val_35,network_id from
Table2 where val_35 is not null
and status='Correct_1');
update Table1 b SET (Val_12,Val_13,Val_14)=
(select Val_12,Val_13,Val_14 from
(select Val_35,network_id, Val_12, Val_13, Val_14
from Table2
where Val_34 is not null
and (REGEXP_LIKE(Val_13,'^[0-9]+$'))
and (Val_14 is null or (REGEXP_LIKE(Val_14,'^[0-9]+$')))
group by Val_35,network_id,Val_12,Val_13,Val_14
)
where Val_35 = b.Val_35 and network_id = b.network_id and rownum=1
)
where status = 'PCStep2' and (regexp_like(Val_13,'[MSS]+') or regexp_like(Val_14,'[MSS]+'));
I tried a lot with my less Knowledge In SQL JOINs. but getting multiple erros.
can anybody help me with the queries at the earliest.
Hearty thanks in advance
Actually you can not mix a update statement with a join statement. An update statement always expects exactly one table definition after the update command.
-- ORA-00971: missing SET keyword
update orders o, customers c
set o.order_value = c.account_value
where o.cust_id = c.cust_id
-- works fine
update orders o
set o.order_value = (select c.account_value
from customers c
where c.id = o.cust_id)

SQL update with count gets only nulls

I am using SQL Server 2008 R2 and SSRS 2008 to generate the report. I am trying to update a table to get a count of the results from another table.
UPDATE r
SET r.Race = d2.Race,
r.RaceNum = d2.count
FROM #results r
INNER JOIN
(SELECT d.Race,
COUNT(d.race) AS 'count'
FROM #Demographic d
GROUP BY d.Race)d2 ON r.Race = d2.Race
An insert works perfectly but I am inserting several times into the results table to create a demographics report. This is creating a lot Null data at the table of the results. If anyone has an idea of what I am going wrong the help would be appreciated.
Not certain, but first guess is that count is a reserved word... change it to something else such as...
update r
set r.Race = d2.Race, r.RaceNum = d2.cnt
from #results r
inner join
(select d.Race, COUNT(d.race) as 'cnt' from #Demographic d group by d.Race)d2
on r.Race = d2.Race
or alternatively try delimiting the column identifier as [count] or if you have quoted identifiers on "count"
Your query is:
update r
set r.Race = d2.Race, /*<---------*/
r.RaceNum = d2.count
from #results r inner join
(select d.Race, COUNT(d.race) as 'count'
from #Demographic d
group by d.Race
) d2
on r.Race = d2.Race /*<-------- */
The two marked lines stand out. You are joining on values using =, then you are setting one equal to the other. This may not be the problem, but it is suspicious. If you are joining on them, why are you setting them equal? My suspicion is that the join is failing, because nothing matches it.
You don't need to update the race column, since that's the equality portion of your join.
As written, any race not in #demographic would have its racenum set to null. If you want 0 for those try:
UDPATE
r
SET
r.RaceNum = ISNULL(d2.ct, 0)
FROM #results r
LEFT JOIN
(
SELECT
d.Race
, COUNT(d.race) as ct
FROM
#Demographic d
GROUP BY
d.Race
) d2
ON
r.Race = d2.Race

Doing an Update Ignore in SQL Server 2005

I have a table where I wish to update some of the rows. All the fields are not null. I'm doing a sub-query, and I wish to update the table with the non-Null results.
See Below for my final answer:
In MySQL, I solve this problem by doing an UPDATE IGNORE. How do I make this work in SQL Server 2005? The sub-query uses a four-table Join to find the data to insert if it exists. The Update is being run against a table that could have 90,000+ records, so I need a solution that uses SQL, rather than having the Java program that's querying the database retrieve the results and then update those fields where we've got non-Null values.
Update: My query:
UPDATE #SearchResults SET geneSymbol = (
SELECT TOP 1 symbol.name FROM
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE joiner.indelID = #SearchResults.id ORDER BY symbol.id ASC)
WHERE isSNV = 0
If I add "AND symbol.name IS NOT NULL" to either WHERE I get a SQL error. If I run it as is I get "adding null to a non-null column" errors. :-(
Thank you all, I ended up finding this:
UPDATE #SearchResults SET geneSymbol =
ISNULL ((SELECT TOP 1 symbol.name FROM
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE joiner.indelID = #SearchResults.id ORDER BY symbol.id ASC), ' ')
WHERE isSNV = 0
While it would be better not to do anything in the null case (so I'm going to try to understand the other answers, and see if they're faster) setting the null cases to a blank answer also works, and that's what this does.
Note: Wrapping the ISNULL (...) with () leads to really obscure (and wrong) errors.
with UpdatedGenesDS (
select joiner.indelID, name, row_number() over (order by symbol.id asc) seq
from
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE name is not null ORDER BY symbol.id ASC
)
update Genes
set geneSymbol = upd.name
from #SearchResults a
inner join UpdateGenesDs upd on a.id = b.intelID
where upd.seq =1 and isSNV = 0
this handles the null completely as all are filtered out by the where predicate (can also be filtered by join predicate if You wish. Is it what You are looking for?
Here's another option, where only those rows in #SearchResults that are succesfully joined will be udpated. If there are no null values in the underlying data, then the inner joins will pull in no null values, and you won't have to worry about filtering them out.
UPDATE #SearchResults
set geneSymbol = symbol.name
from #SearchResults sr
inner join IndelConnector AS joiner
on joiner.indelID = sr.id
inner join Result AS sSeq
on sSeq.id = joiner.sSeqID
inner join GeneConnector AS geneJoin
on geneJoin.sSeqID = sSeq.id
-- Get "lowest" (i.e. first if listed alphabetically) value of name for each id
inner join (select id, min(name) name
from GeneSymbol
group by id) symbol
on symbol.id = geneJoin.geneSymbolID
where isSNV = 0 -- Which table is this value from?
(There might be some syntax problems, without tables I can't debug it)