Yet another subquery issue - sql-server

Hello from an absolute beginner in SQL!
I have a field I want to populate based on another table. For this I have written this query, which fails with: Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
oK, here goes:
Update kre.CustomerOrderLineCopy
SET DepNo = (SELECT customerordercopy.DepNo
FROM kre.CustomerOrderCopy , kre.CustomerOrderLineCopy
WHERE CustomerOrderLineCopy.OrderCopyNo =kre.CustomerOrderCopy.OrderCopyNo)
WHERE CustomerOrderLineCopy.OrderCopyNo = (SELECT CustomerOrderCopy.OrderCopyNo
FROM kre.CustomerOrderCopy, kre.CustomerOrderLineCopy
WHERE kre.CustomerOrderLineCopy.OrderCopyNo = kre.CustomerOrderCopy.OrderCopyNo)
What I'm trying to do is to change DepNo in CustomerOrderLineCopy, with the value in DepNo in CustomerOrderCopy - based on the same OrderCopyNo in both tables.
I'm open for all suggestion.
Thanks,
ohalvors

If you just join the tables together the update is easier:
UPDATE A SET A.DepNo = B.DepNo
FROM kre.CustomerOrderLineCopy A
INNER JOIN kre.CustomerOrderCopy B ON A.OrderCopyNo = B.OrderCopyNo

The problem is that at least one of your sub queries return more than one value. Think about this:
tablePerson(name, age)
Adam, 11
Eva, 11
Sven 22
update tablePerson
set name = (select name from tablePerson where age = 11)
where name = 'Sven'
Which is equivalent to: set Sven's name to Adam and Eva. Which is not possible.
If you want to use sub queries, either make sure your sub queries can only return one value or force one value by using:
select top 1 xxx from ...

This may be enough to quieten it down:
Update kre.CustomerOrderLineCopy
SET DepNo = (SELECT customerordercopy.DepNo
FROM kre.CustomerOrderCopy --, kre.CustomerOrderLineCopy
WHERE CustomerOrderLineCopy.OrderCopyNo =kre.CustomerOrderCopy.OrderCopyNo)
WHERE CustomerOrderLineCopy.OrderCopyNo = (SELECT CustomerOrderCopy.OrderCopyNo
FROM kre.CustomerOrderCopy --, kre.CustomerOrderLineCopy
WHERE kre.CustomerOrderLineCopy.OrderCopyNo = kre.CustomerOrderCopy.OrderCopyNo)
(Where I've commented out kre.CustomerOrderLineCopy in the subqueries) That is, you were hopefully trying to correlate these subqueries with the outer table - not introduce another instance of kre.CustomerOrderLineCopy.
If you still get an error, then you still have multiple rows in kre.CustomerOrderCopy which have the same OrderCopyNo. If that's so, you need to give us (and SQL Server) the rules that you want to apply for how to select which row you want to use.
The danger of switching to the FROM ... JOIN form shown in #Avitus's answer is that it will no longer report if there are multiple matching rows - it will just silently pick one of them - which one is never made clear.
Now I look at the query again, I'm not sure it even needs a WHERE clause now. I think this is the same:
Update kre.CustomerOrderLineCopy
SET DepNo = (
SELECT customerordercopy.DepNo
FROM kre.CustomerOrderCopy
WHERE CustomerOrderLineCopy.OrderCopyNo = kre.CustomerOrderCopy.OrderCopyNo)

Related

What is wrong with my UPDATE statement WHERE NOT EXISTS?

What I am trying to accomplish is to update the ISCURRENT field to 'N' and the EFFECTIVE_END_DATE field to the current date if the record of its type does not have the most recent EFFECTIVE_START_DATE.
An error does not get thrown it just tells me "0 rows affected" but I created a record with a more recent EFFECTIVE_START_DATE which should affect the other record in the table that has the earlier EFFECTIVE_START_DATE.
Here is an image of the 2 records I'm using to test it out.
The record that has a KTEXT of '400 Atlantic' should be changed from this script to have an ISCURRENT ='N' and EFFECTIVE_END_DATE=GETDATE() because the record with the KTEXT of 500 Maria has a more recent EFFECTIVE_START_DATE
UPDATE [SAP].[src_gl_sap_m_cepct]
set ISCURRENT='N',
EFFECTIVE_END_DATE=GETDATE()
WHERE NOT EXISTS (SELECT [SPRAS],
[PRCTR],
MAX(EFFECTIVE_START_DATE)
FROM [SAP].[src_gl_sap_m_cepct] AS A
WHERE CONCAT([SAP].[src_gl_sap_m_cepct].[SPRAS],[SAP].[src_gl_sap_m_cepct].[PRCTR]) = CONCAT(A.[SPRAS],A.[PRCTR]
)
GROUP BY [SPRAS],[PRCTR]);
Thank you !
Correct me if I am wrong, but this part of your query
FROM [SAP].[src_gl_sap_m_cepct] AS A
WHERE CONCAT([SAP].[src_gl_sap_m_cepct].[SPRAS],[SAP].[src_gl_sap_m_cepct].[PRCTR]) = CONCAT(A.[SPRAS],A.[PRCTR]
can also be written like this (because you have a self join)
FROM [SAP].[src_gl_sap_m_cepct] AS A
WHERE CONCAT(A.[SPRAS], A.[PRCTR]) = CONCAT(A.[SPRAS], A.[PRCTR]
And like this I notice that you are simply comparing a value to the same value again.
Thus this will always evaluate as TRUE
And thus the not exists clause will never evaluate as true
And therefore no updates will happen.
I think something like this might work for you
UPDATE c
set c.ISCURRENT='N',
c.EFFECTIVE_END_DATE = GETDATE()
FROM SAP.src_gl_sap_m_cepct c
WHERE EXISTS ( select 1
FROM SAP.src_gl_sap_m_cepct AS A
WHERE CONCAT(c.SPRAS, c.PRCTR) = CONCAT(A.SPRAS, A.PRCTR)
AND A.EFFECTIVE_START_DATE > c.EFFECTIVE_START_DATE
)
If I understood correctly, the statement should be like this:
UPDATE c
set ISCURRENT='N',
EFFECTIVE_END_DATE = GETDATE()
FROM [SAP].[src_gl_sap_m_cepct] c
WHERE EXISTS (
SELECT 1
FROM [SAP].[src_gl_sap_m_cepct] AS A
WHERE CONCAT(c.[SPRAS], c.[PRCTR]) = CONCAT(A.[SPRAS],A.[PRCTR])
AND c.EFFECTIVE_START_DATE < A.EFFECTIVE_START_DATE
);

Ignoring Nulls using Lag() in SQL Server 2018

I am trying to get the Activity ID linked to Dispatch. In the data Attrib_43 will only get populated if Dispatch is created.
What i am looking to do is to get the Activity ID of the previous row before the Dispatch created.
Attached is the code that i am using
Select sea.ROW_ID, sea.CREATED_DTTM,sea.SRA_SR_ID,sea.ATTRIB_43, tsk.CRT_DTS, tsk.TASK_DESC, datediff(ss,sea.CREATED_DTTM, tsk.CRT_DTS) as dd
, seal.x_isp_notes, seal.x_isp_comments, seal.comments, seal.x_isp_agent_desc
, tsk.TASK_SUB_TYPE_CD, tsk.TASK_TYPE_CD, tsk.WHAT_ID
, cdl.ORIGIN_NM
,LAG(sea.ROW_ID,1) over (partition by sea.ATTRIB_43 order by sea.CREATED_DTTM) AS 'FLAGID'
--, tsk.*,
, fdc.FISCAL_QUARTER
from GSEDATA.dbo.X_ISP_EXTRNL_CASE_ID sea
join rawdata.corp_ww.FISCAL_DAY_CALENDAR fdc on sea.CREATED_DATE = fdc.ACTUAL_DATE
left join rawdata.svc_base.SFDC_TASK_DTL tsk on sea.X_ISP_EXTRNL_CASE_ID = tsk.TASK_ID
left join rawdata.svc_base.SFDC_CASE_DTL cdl on cdl.case_id = tsk.what_id
left join GSEDATA.dbo.s_evt_act_logs seal on sea.ROW_ID = seal.row_id
where --sea.ATTRIB_43 = '04391481876'
sea.SRA_SR_ID = 'A-2Q7YF57W'
order by sea.CREATED_DTTM
But it is not working as per my Expectation - Activity ID flag for Attrib 43 is coming as Null
If I understand your question correctly, you are getting null FLAGID for non- null attrib_43 becuase you are using a partition by sea.ATTRIB_43 clause.
Partition by divides the query result set into partitions. The window function is applied to each partition separately and computation restarts for each partition.
That is why the null values for ATTRIB_43 are grouped into one window and the non-null ATTRIB_43 will have a separate window for each distinct value, therefore giving a NULL for LAG() function in the first row of each window.
you should remove the clause partition by sea.ATTRIB_43 if you want lag values for all rows.
LAG(sea.ROW_ID,1) over (order by sea.CREATED_DTTM) AS 'FLAGID'

Subquery returned more than 1 value causing query to fail

I'm stuck with this query. i want to show a field called "Executive" that must say "sin asignar" if there's no match when joining on the table 'prospectousuario', and if it exist it must say the first and the last name of the executive. But it returns the following error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an exp
The query is:
select p.IDCANCAP,
p.CEDULA,
p.NOMBRES,
p.APELLIDOS,
p.CELULAR,
p.CASA,
p.CORREO,
p.ESTABLECIMIENTO,
c.DESCRIPCION,
(select case when
p.CEDULA = pu.IDPROSPECTO and pu.IDUSUARIO = u.CEDULA
then u.NOMBRES+' '+u.APELLIDOS else 'Sin asignar'
end from usuario as u, PROSPECTOUSUARIO as pu) as Ejecutivo,
p.FECHA_CREAC
from PROSPECTO p, CANALCAPTACION c
where p.IDCANCAP = c.IDCANAL
Boy this is a guess, based on your SQL and a lot of reading between the lines... but give it a try:
select p.IDCANCAP, p.CEDULA, p.NOMBRES,
p.APELLIDOS, p.CELULAR,p.CASA, p.CORREO,
p.ESTABLECIMIENTO, c.DESCRIPCION, p.FECHA_CREAC,
case when exists
(Select * from PROSPECTOUSUARIO
Where IDPROSPECTO = p.CEDULA)
then u.NOMBRES+' '+ u.APELLIDOS
else 'Sin asignar' end Ejecutivo
from PROSPECTO p
join CANALCAPTACION c on c.IDCANAL = p.IDCANCAP
join usuario u on u.CEDULA = p.CEDULA
Just as the error message says, your one and only subquery
(select case when
p.CEDULA = pu.IDPROSPECTO and pu.IDUSUARIO = u.CEDULA
then u.NOMBRES+' '+u.APELLIDOS else 'Sin asignar'
end from usuario as u, PROSPECTOUSUARIO as pu)
returns more than 1 row, which is not allowed when used as an expression inside the SELECT. In fact, it appears that the u and pu tables are not joined against any other tables in any meaningful way.
To fix, you must join the tables. In fact, you don't even need a subquery for what you're trying to do - move all tables to the FROM section and join them properly, whether inner or outer. Unfortunately, I don't know which fields they should be joined on, so I can't help there without more information or wild guessing.

SQL Server LEFT JOIN

This query has been keeping me busy for the last couple of days. I tried to rewrite it with different ideas but I keep having the same problem. To simplify the problem I put part of my query in a view, this view returns 23 records. Using a left join I would like to add fields coming from the table tblDatPositionsCalc to these 23 records. As you can see I have an additional condition on the tblDatPositionsCalc in order to only consider the most recent records. With this condition it would return 21 records. The join should be on two fields together colAccount and colId.
I simply want the query to return the 23 records from the view and where possible have the information from tblDatPositionsCalc. There is actually only 2 records in the view without corresponding id and account in tblDatPositionsCalc, that means out of the 23 records only 2 will have missing values in the fields coming from the table tblDatPositionsCalc.
The problem with my query is that it only returns the 21 records from tblDatPositionsCalc. I don't understand why. I tried to move the condition on date in just after the JOIN condition but that did not help.
SELECT TOP (100) PERCENT
dbo.vwCurrPos.Account,
dbo.vwCurrPos.Id,
dbo.vwCurrPos.TickerBB,
dbo.vwCurrPos.colEquityCode,
dbo.vwCurrPos.colType,
dbo.vwCurrPos.colCcy,
dbo.vwCurrPos.colRegion,
dbo.vwCurrPos.colExchange,
dbo.vwCurrPos.[Instr Type],
dbo.vwCurrPos.colMinLastDay,
dbo.vwCurrPos.colTimeShift,
dbo.vwCurrPos.Strike,
dbo.vwCurrPos.colMultiplier,
dbo.vwCurrPos.colBetaVol,
dbo.vwCurrPos.colBetaEq,
dbo.vwCurrPos.colBetaFloor,
dbo.vwCurrPos.colBetaCurv,
dbo.vwCurrPos.colUndlVol,
dbo.vwCurrPos.colUndlEq,
dbo.vwCurrPos.colUndlFut,
tblDatPositionsCalc_1.colLots,
dbo.vwCurrPos.[Open Positions],
dbo.vwCurrPos.colListMatShift,
dbo.vwCurrPos.colStartTime,
tblDatPositionsCalc_1.colPrice,
tblDatPositionsCalc_1.colMktPrice,
dbo.vwCurrPos.colProduct,
dbo.vwCurrPos.colCalendar,
CAST(dbo.vwCurrPos.colExpiry AS DATETIME) AS colExpiry,
dbo.vwCurrPos.colEndTime,
CAST(tblDatPositionsCalc_1.colDate AS datetime) AS colDate,
dbo.vwCurrPos.colFund,
dbo.vwCurrPos.colExchangeTT,
dbo.vwCurrPos.colUserTag
FROM dbo.vwCurrPos
LEFT OUTER JOIN dbo.tblDatPositionsCalc AS tblDatPositionsCalc_1
ON tblDatPositionsCalc_1.colId = dbo.vwCurrPos.Id
AND tblDatPositionsCalc_1.colAccount = dbo.vwCurrPos.Account
WHERE (tblDatPositionsCalc_1.colDate =
(SELECT MAX(colDate) AS Expr1 FROM dbo.tblDatPositionsCalc))
ORDER BY
dbo.vwCurrPos.Account,
dbo.vwCurrPos.Id,
dbo.vwCurrPos.colEquityCode,
dbo.vwCurrPos.colRegion
Any idea what might cause the problem?
(Option 1) DrCopyPaste is right so your from clause would look like:
...
FROM dbo.vwCurrPos
LEFT OUTER JOIN dbo.tblDatPositionsCalc AS tblDatPositionsCalc_1
ON tblDatPositionsCalc_1.colId = dbo.vwCurrPos.Id
AND tblDatPositionsCalc_1.colAccount = dbo.vwCurrPos.Account
and (tblDatPositionsCalc_1.colDate =
(SELECT MAX(colDate) AS Expr1 FROM dbo.tblDatPositionsCalc))
...
reason: the where clause restriction of left joined to column = some expression with fail to return for "null = something" so the row will be removed.
(Option 2) As oppose to pushing code in to additional views where it is harder to maintain you can nest sql select statements;
select
X.x1,X.x2,
Y.*
from X
left join
(select Z.z1 as y1, Z.z2 as y2, Z.z3 as y3
from Z
where Z.z1 = (select max(Z.z1) from Z)
) as Y
on x.x1 = Y.y1 and X.x2 = Y.y2
The advantage here is you check each nested sub query a move out quickly. Although if you still building up more logic check out common table expressions (CTE's) http://msdn.microsoft.com/en-us/library/ms175972.aspx

Missing data row in NOT IN clause

I just realised that my Auto-Price Calculation doesn't fill the Prices for ListID 4.
I inserted the Prices from the SELECT shown below.
For bugg research I executed the SELECT without the WHERE part and it shows me the example data row.
I can't find the error though, why it is not shown in the complete select (it has no entry with ListID = 4).
Someone can see my mistake?
Edit: Just tried the subselect alone, it shows no rows for the requested article. Why is the NOT IN clause unaffected by this fact?
Most likely, it's because of how you are combining the artikelnummer and the auspraegungID.
I do not think you have accounted for that fact that '100' + '0' is idential to '10' + '00'.
Instead of trying to merge two fields into one, perhaps try the following?
SELECT
*
FROM
#allArticles AS allArticles
WHERE
Artikelnummer = 'IT-810260'
AND NOT EXISTS (SELECT *
FROM KHKPreisListenArtikel
WHERE ListeID = 4
AND Artikelnummer = allArticles.Artikelnummer
AND Auspraegung = allArticles.Auspraegung
)
If that still doesn't work, then you must have corresponding records in that other table, find them like this...
SELECT
*
FROM
#allArticles AS allArticles
INNER JOIN
KHKPreisListenArtikel AS Preis
ON Preis.ListeID = 4
AND Preis.Artikelnummer = allArticles.Artikelnummer
AND Preis.Auspraegung = allArticles.Auspraegung
WHERe
allArticles.Artikelnummer = 'IT-810260'
PLEASE ALSO NOTE
Please don't include images of code, please copy the code, so that we can copy it too.
Especially when the tables/fields are in another language...
EDIT
Here is a query that will show the cause of your original query to fail.
SELECT
*
FROM
#allArticles AS allArticles
INNER JOIN
KHKPreisListenArtikel AS Preis
ON Preis.ListeID = 4
AND Preis.Artikelnummer + CONVERT(VARCHAR(50), Preis.Auspraegung)
=
allArticles.Artikelnummer + CONVERT(VARCHAR(50), allArticles.Auspraegung)
WHERE
allArticles.Artikelnummer = 'IT-810260'

Resources