SQL issue - The column 'Id' was specified multiple times for 'sv2017' - sql-server

I keep receiving the error
Msg 8156, Level 16, State 1, Line 5
The column 'Id' was specified multiple times for 'sv2017'.
Msg 8156, Level 16, State 1, Line 7
The column 'Id' was specified multiple times for 'sv2010'.
with the following script:
select
sv2017.id, sv2017.TotalArea, sv2017.uarn,
sv2010.id, sv2010.PlantMachineryValue, sv2017.PlantMachineryValue,
sv2010.uarn, sv2017.BAReferenceNumber
from
(select *
from summaryvaluation sv
join SummaryValuationPlant svp on sv.id = svp.SummaryValuationId
where sv.yearid = 2
and sv.id in (select id /*Get the most recent valuation for the list year*/
from
(select
id, uarn,
rank() over (partition by uarn order by fromdate desc) as RankOrder
from
summaryvaluation
where
yearid = 2 and systemactive = 1) tbl
where
rankorder = 1)) sv2017
left outer join
(select *
from summaryvaluation sv2
join SummaryValuationPlant svp2 on sv2.id = svp2.SummaryValuationId
where sv2.yearid = 1
and sv2.id in (select id /*Get the most recent valuation for the list year*/
from
(select
id, uarn,
rank() over (partition by uarn order by fromdate desc) as RankOrder
from
summaryvaluation
where
yearid = 1 and systemactive = 1) tbl
where
rankorder = 1)) sv2010 on sv2017.uarn = sv2010.uarn
where
isnull (sv2017.PlantMachineryValue, 0) > isnull(sv2010.PlantMachineryValue, 0)
and I can not see where I am going wrong! It is probably obvious and my brain is just not functioning but any help is appreciated.
Thanks

Your problem is probably here:
select *
from summaryvaluation sv
join SummaryValuationPlant svp
That code appears in 2 different places (with different aliases). Regardless, I suspect both tables have an id column, so when you use this in a derived table, SQL doesn't know if you are referring to the one from the sv table or the svp table.
To correct this problem, remove the * and list just those columns you will be using elsewhere in the larger query.

Related

How to remove duplicates in a SQL query?

I have a query that is built for an specific filter that I want to re-structure it to provide me an output for all records, but it is creating duplicate sum values.
The initial query I have is as follows:
SELECT
CustomerNo,
(SELECT SUM(Amount)
FROM DetailedCustLedgEntry DLE
WHERE
DLE.PostingDate <= '2019-12-16' AND
DLE.[Entry Type] In (1,3,4,5,6,7,8,9,12,13,14,15,16,17) AND
DLE.CustLedgerEntryNo = CLE.EntryNo) as TotalAmount,
--Amt Modifer 1
(SELECT SUM(ClosedByAmount)
FROM CustLedgerEntry
WHERE
"Closed by EntryNo" = CLE.EntryNo AND
PostingDate <= '2019-12-16') as AmtModifer1,
--Amt Modifier 2
(SELECT SUM(ClosedByAmount * -1)
FROM CustLedgerEntry
WHERE
EntryNo = CLE."Closed by EntryNo" AND
PostingDate <= '2019-12-16') as AmtModifer2
FROM
CustLedgerEntry CLE
WHERE
CustomerNo = '104421' AND
"Open"=1 AND
Branch='D--HE-001' AND
PostingDate<='2019-12-17'
The query above filters by CustomerNo = '104421', but I want to be able to see all customers.
I have created joints as follows:
SELECT
CLE.CustomerNo,
SUM(DLE.Amount) as TotalAmount,
SUM(CLE_AM1.ClosedByAmount) as AmtModifer1,
SUM(CLE_AM2.ClosedByAmount * -1) as AmtModifer2
INTO
#TempCLE
FROM
CustLedgerEntry CLE
LEFT JOIN
DetailedCustLedgEntry DLE ON DLE.CustLedgerEntryNo = CLE.EntryNo
LEFT JOIN
CustLedgerEntry CLE_AM1 ON CLE_AM1."Closed by EntryNo" = CLE.EntryNo
LEFT JOIN
CustLedgerEntry CLE_AM2 ON CLE_AM2.EntryNo = CLE."Closed by EntryNo"
WHERE
CLE."Open" = 1 AND
CLE.Branch = 'D--HE-001' AND
CLE.PostingDate <= '2019-12-17' and
DLE.PostingDate <= '2019-12-16' AND
DLE.[Entry Type] IN (1,3,4,5,6,7,8,9,12,13,14,15,16,17)
GROUP BY
CLE.CustomerNo
The problem I have is that the TotalAmount seems to duplicate the output (like, sum the value twice, instead of 2 I see 4)
If I remove the joints for CLE_AM1 and CLE_AM2 the duplicates. I'm guessing the problem is in these joints, but I don't see how they should be build instead
LEFT JOIN
"Bobcat Bensheim GmbH$Cust_ Ledger Entry" CLE_AM1 ON CLE_AM1."Closed by Entry No_" = CLE."Entry No_"
LEFT JOIN
"Bobcat Bensheim GmbH$Cust_ Ledger Entry" CLE_AM2 ON CLE_AM2."Entry No_" = CLE."Closed by Entry No_"
Any ideas?

Returning a single date with max(date)

I have the following query. I want to retrieve a list of unique Object ID's with the value closest to a specified date:
INSERT INTO #temp
(
[Object ID]
,[Waarde]
,[Kenmerk]
)
select DISTINCT PME.OBJECTID,
LEFT(PME.OBJECTSCORINGVALUE,LEN(PME.OBJECTSCORINGVALUE)-2),
'P3'
FROM PMEOBJECTSCORINGPOINTS PME
LEFT JOIN PMEOBJECTSCORINGHISTORY PMEH ON PME.OBJECTSCORINGHISTORYID = PMEH.OBJECTSCORINGHISTORYID
INNER JOIN(SELECT OBJECTSCORINGHISTORYID, MAX(DATE) DATE
FROM PMEOBJECTSCORINGHISTORY
WHERE DATE < DATEFROMPARTS(YEAR(getdate())-1, 12, 31)
GROUP BY OBJECTSCORINGHISTORYID) P3 ON PME.OBJECTSCORINGHISTORYID = P3.OBJECTSCORINGHISTORYID
AND PMEH.DATE = P3.DATE
AND PME.ATTRIBUTEID = 'Energie-idx'
AND PME.OBJECTSCORINGVALUE <> ''
------------------
select * from #temp
order by [Object ID], [Kenmerk] ASC
When a certain Object ID only has one known value before 2019-12-31, I get one record in the result set. However, if an Object ID has two (or more) known values before that date, I still get multiple results instead of the value for the date closest to 2019-12-31.
Any pointers on how to get the desired results? Thanks in advance!
(edit: apologies for the bad readibility on the code, thanks for fixing it)
Use analytical funtion ROW_NUMBER(), if you can sort on a column, Perhaps P3.Date or PME.OBJECTSCORINGVALUE
select Objectid, OBJECTSCORINGVALUE,P3
from(
select PME.OBJECTID,
LEFT(PME.OBJECTSCORINGVALUE,LEN(PME.OBJECTSCORINGVALUE)-2) OBJECTSCORINGVALUE,
'P3' Pcol,P3.Date
row_number() over (partition by PME.OBJECTID, LEFT(PME.OBJECTSCORINGVALUE,LEN(PME.OBJECTSCORINGVALUE)-2) order by P3.Date DESC) rn
FROM PMEOBJECTSCORINGPOINTS PME
LEFT JOIN PMEOBJECTSCORINGHISTORY PMEH ON PME.OBJECTSCORINGHISTORYID = PMEH.OBJECTSCORINGHISTORYID
INNER JOIN(SELECT OBJECTSCORINGHISTORYID, MAX(DATE) DATE
FROM PMEOBJECTSCORINGHISTORY
WHERE DATE < DATEFROMPARTS(YEAR(getdate())-1, 12, 31)
GROUP BY OBJECTSCORINGHISTORYID) P3 ON PME.OBJECTSCORINGHISTORYID = P3.OBJECTSCORINGHISTORYID
AND PMEH.DATE = P3.DATE
AND PME.ATTRIBUTEID = 'Energie-idx'
AND PME.OBJECTSCORINGVALUE <> ''
) where rn=1
Here I order the replies with P3.Date, and return only the one with the highest value.
It is guaranteed to only return one row, however you have to be sure about your data to be sure that it is deterministic
I fixed the problem. Turned out I did an incorrect join (wrong level of granularity). I should have done it on OBJECTID instead of OBJECTSCORINGHISTORYID. The result was that the max(date) was returned for OBJECTSCORINGHISTORYID instead of on the level of OBJECTID.
This is the correct query:
INSERT INTO #temp
(
[Object ID]
,[Waarde]
,[Kenmerk]
)
select PME.OBJECTID,
LEFT(PME.OBJECTSCORINGVALUE,LEN(PME.OBJECTSCORINGVALUE)-2),
'P3'
FROM PMEOBJECTSCORINGPOINTS PME
LEFT JOIN PMEOBJECTSCORINGHISTORY PMEH ON PME.OBJECTSCORINGHISTORYID = PMEH.OBJECTSCORINGHISTORYID
INNER JOIN(SELECT OBJECTID, MAX(DATE) DATE
FROM PMEOBJECTSCORINGHISTORY
WHERE DATE < DATEFROMPARTS(YEAR(getdate())-1, 12, 31)
GROUP BY OBJECTID) P3 ON PME.OBJECTID = P3.OBJECTID
AND PMEH.DATE = P3.DATE
AND PME.ATTRIBUTEID = 'Energie-idx'
AND PME.OBJECTSCORINGVALUE <> ''

SQL Query Get Last record Group by multiple fields

Hi I have a table with following fields:
ALERTID POLY_CODE ALERT_DATETIME ALERT_TYPE
I need to query above table for records in the last 24 hour.
Then group by POLY_CODE and ALERT_TYPE and get the latest Alert_Level value ordered by ALERT_DATETIME
I can get up to this, but I need the AlertID of the resulting records.
Any suggestions what would be an efficient way of getting this ?
I have created an SQL in SQL Server. See below
SELECT POLY_CODE, ALERT_TYPE, X.ALERT_LEVEL AS LAST_ALERT_LEVEL
FROM
(SELECT * FROM TableA where ALERT_DATETIME >= GETDATE() -1) T1
OUTER APPLY (SELECT TOP 1 [ALERT_LEVEL]
FROM (SELECT * FROM TableA where ALERT_DATETIME >= GETDATE() -1) T2
WHERE T2.POLY_CODE = T1.POLY_CODE AND
T2.ALERT_TYPE = T1.ALERT_TYPE ORDER BY T2.[ALERT_DATETIME] DESC) X
GROUP BY POLY_CODE, ALERT_TYPE, X.[ALERT_LEVEL]
POLY_CODE ALERT_TYPE ALERT_LEVEL
04575 Elec 2
04737 Gas 3
06239 Elec 2
06552 Elec 2
06578 Elec 2
10320 Elec 2
select top 1 with ties *
from TableA
where ALERT_DATETIME >= GETDATE() -1
order by row_number() over (partition by POLY_CODE,ALERT_TYPE order by [ALERT_DATETIME] DESC)
The way this works is that for each group of POLY_CODE,ALERT_TYPE get their own row_number() starting from the most recent alert_datetime. Then, the with ties clause ensures that all rows(= all groups) with the row_number value of 1 get returned.
One way of doing it is creating a cte with the grouping that calculates the latesdatetime for each and then crosses it with the table to get the results. Just keep in mind that if there are more than one record with the same combination of poly_code, alert_type, alert_level and datetime they will all show.
WITH list AS (
SELECT ta.poly_code,ta.alert_type,MAX(ta.alert_datetime) AS LatestDatetime,
ta.alert_level
FROM dbo.TableA AS ta
WHERE ta.alert_datetime >= DATEADD(DAY,-1,GETDATE())
GROUP BY ta.poly_code, ta.alert_type,ta.alert_level
)
SELECT ta.*
FROM list AS l
INNER JOIN dbo.TableA AS ta ON ta.alert_level = l.alert_level AND ta.alert_type = l.alert_type AND ta.poly_code = l.poly_code AND ta.alert_datetime = l.LatestDatetime

Oracle get only last 1 row data on multiple tables query

I have an Oracle query to get only last 1 row data.
SELECT
R.FORM_NO,
R.PART_NO,
L.L_FORM_NO,
L.HDR_ID,
L.CP_ID_SLC_FORM_NO,
S.FORM_NO,
S.PART_NO,
S.CP_ID
FROM
WA_T_QC_REVISION R,
WA_T_QC_REVISION_LIST L,
WA_T_QC_CP_SELECTED S
WHERE
R.FORM_NO = L.HDR_ID AND
S.FORM_NO = L.CP_ID_SLC_FORM_NO AND
R.PART_NO = 'PA03670-B501'
ORDER BY R.FORM_NO DESC
When I try to adding the query to be like this:
SELECT * FROM(
SELECT
R.FORM_NO,
R.PART_NO,
L.L_FORM_NO,
L.HDR_ID,
L.CP_ID_SLC_FORM_NO,
S.FORM_NO,
S.PART_NO,
S.CP_ID
FROM
WA_T_QC_REVISION R,
WA_T_QC_REVISION_LIST L,
WA_T_QC_CP_SELECTED S
WHERE
R.FORM_NO = L.HDR_ID AND
S.FORM_NO = L.CP_ID_SLC_FORM_NO AND
R.PART_NO = 'PA03670-B501'
ORDER BY R.FORM_NO DESC)
WHERE ROWNUM <= 1
I got an error
ORA-00918: column ambiguously defined
What I want is to get only last 1 row data from tables.
The immediate fix here is to just alias the columns having the same name such that they no longer have the same name, e.g.
SELECT * FROM (
SELECT
R.FORM_NO AS FORM_NO_R,
R.PART_NO AS PART_NO_R,
L.L_FORM_NO,
L.HDR_ID,
L.CP_ID_SLC_FORM_NO,
S.FORM_NO AS FORM_NO_S,
S.PART_NO AS PART_ON_S,
S.CP_ID
FROM WA_T_QC_REVISION R
INNER JOIN WA_T_QC_REVISION_LIST L
ON R.FORM_NO = L.HDR_ID
INNER JOIN WA_T_QC_CP_SELECTED S
ON S.FORM_NO = L.CP_ID_SLC_FORM_NO
WHERE
R.PART_NO = 'PA03670-B501'
ORDER BY R.FORM_NO DESC
)
WHERE ROWNUM <= 1
Note also that I replaced your implicit joins with explicit inner joins. Using formal join syntax is the preferred way of writing queries (and has been for more than 25 years).

SELECT most recent date out of group

I have a T-SQL query that is designed to weed out duplicate entries of a certain product training, grabbing only the one with the most recent DateTaken. For example, if someone has taken a certain training course 3 times, we only want to display one row, that row being the one that contains the most recent DateTaken. Here is what I have so far, however I am receiving the following error:
An expression of non-boolean type specified in a context where a condition is expected, near 'ORDER'.
The ORDER BY is necessary since we want to group all the results of this query by the expiration date. Below is the full query:
SELECT DISTINCT
p.ProductDescription as ProductDesc,
c.CourseDescription as CourseDesc,
c.Partner, a.DateTaken, a.DateExpired, p.Status
FROM
sNumberToAgentId u, AgentProductTraining a, Course c, Product p
WHERE
#agentId = u.AgentId
and u.sNumber = a.sNumber
and a.CourseCode = c.CourseCode
and (a.DateExpired >= #date or a.DateExpired IS NULL)
and a.ProductCode = p.ProductCode
and (p.status != 'D' or p.status IS NULL)
GROUP BY
(p.ProductDescription)
HAVING
MIN(a.DateTaken)
ORDER BY
DateExpired ASC
EDIT
I've made the following changes to the GROUP BY and HAVING clauses, however I am still receiving errors:
GROUP BY
(p.ProductDescription, c.CourseDescription)
HAVING
MIN(a.DateTaken) > GETUTCDATE()
In SQL Management Studio, and red line error marker appears under the ',' after p.ProductDescription, the ')' after c.CourseDescription, the 'a' in a.DateTaken, and the closing parenthesis ')' of GETUTCDATE(). If I simply leave the GROUP BY statement to include only p.ProductDescription I get this error message:
Column 'Product.ProductDescription' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I'm relatively new to SQL, could someone explain what's going on? Thank you!
My suggestion since you are using sql server is to implement row_number() and partition by the ProductDescription and CourseDescription. This will go in a subquery and then you apply a filter to return only those where the row number is equal to one or the most recent record:
select *
from
(
SELECT p.ProductDescription as ProductDesc,
c.CourseDescription as CourseDesc,
c.Partner, a.DateTaken, a.DateExpired, p.Status
row_number() over(partition by p.ProductDescription, c.CourseDescription order by a.DateTaken desc) rn
FROM sNumberToAgentId u
INNER JOIN AgentProductTraining a
ON u.sNumber = a.sNumber
AND (a.DateExpired >= #date or a.DateExpired IS NULL)
INNER JOIN Course c
ON a.CourseCode = c.CourseCode
INNER JOIN Product p
ON a.ProductCode = p.ProductCode
AND (p.status != 'D' or p.status IS NULL)
WHERE u.AgentId = #agentId
) src
where rn = 1
order by DateExpired
Its this line
HAVING MIN(a.DateTaken)
Should be a boolean type such as
HAVING MIN(a.DateTaken) > GETUTCDATE()
Have to return True or a False (Boolean)
Here is the final query I wound up using. It is similar to the suggestions above:
SELECT ProductDesc, CourseDesc, Partner, DateTaken, DateExpired, Status
FROM(
SELECT
p.ProductDescription as ProductDesc,
c.CourseDescription as CourseDesc,
c.Partner, a.DateTaken, a.DateExpired, p.Status,
row_number() OVER (PARTITION BY p.ProductDescription, c.CourseDescription ORDER BY abs(datediff(dd, DateTaken, GETDATE()))) as Ranking
FROM
sNumberToAgentId u, AgentProductTraining a, Course c, Product p
WHERE
#agentId = u.AgentId
and u.sNumber = a.sNumber
and a.CourseCode = c.CourseCode
and (a.DateExpired >= #date or a.DateExpired IS NULL)
and a.ProductCode = p.ProductCode
and (p.status != 'D' or p.status IS NULL)
) aa
WHERE Ranking = '1'

Resources