Oracle get only last 1 row data on multiple tables query - database

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).

Related

Filtering a table based on a non-unique column to give only unique fields in SQL

How would I filter out a table that it only includes one value for a column (it does not matter which one).
The SQL query used to create the below looks like this :
SELECT DISTINCT
S.Id AS ReferenceID,
M.NewModuleID AS ModuleId,
SM.Compulsory
FROM
Struct S
INNER JOIN
StructModule SM
ON SM.StructId = S.Id
INNER JOIN
ModuleMap M
ON M.StructId = S.Id
AND SM.ModuleId = M.OldModuleId
However this does not return the values in the way that I need it. the return table looks like this:
ReferenceID NewModuleID Compulsory
1 100 1
1 210 0
2 251 1
2 251 0
However I would like the SQL query to return a unique value for the NewModuleID field. Ideally taking the first occurrence of a value
the relevant columns of the above tables are as follows:
Struct:
ID (INT)
StructModule:
ID (INT)
StructID (INT)
ModuleID (INT)
Compulsory (BIT)
ModuleMap:
ID (INT)
OldModuleId (INT)
StructID (INT)
NewModuleID (INT)
Your question is not very clear, but after reading following statement.
However I would like the SQL query to return a unique value for the
NewModuleID field. Ideally taking the first occurrence of a value
I can guess that you are looking for something like following query.
SELECT * FROM
(
SELECT
S.Id AS ReferenceID,
M.NewModuleID AS ModuleId,
SM.Compulsory ,
ROW_NUMBER() OVER(PARTITION BY S.ID, M.NewModuleID ORDER BY M.NewModuleID) RN
FROM
Struct S
INNER JOIN
StructModule SM
ON SM.StructId = S.Id
INNER JOIN
ModuleMap M
ON M.StructId = S.Id
AND SM.ModuleId = M.OldModuleId
)T
WHERE RN=1
Note : You don't need distinct if you are using RN=1 condition.

Replacement for UPDATE statement with ORDER BY clause

I am having a hard time trying to execute an update query that should contain ORDER BY clause, but I'm unable to find a proper solution yet.
UPDATE I
SET RefItemID = AQ.ID,
I.MagParamNum = AQ.MagParamNum
FROM SRO_VT_SHARD.._Items I
JOIN SRO_VT_SHARD.._Inventory INV ON INV.ItemID = I.ID64
JOIN SRO_VT_SHARD.._RefObjCommon ROC ON ROC.ID = I.RefItemID
JOIN _AEQItems AQ ON AQ.TypeID3 = ROC.TypeID3
AND AQ.TypeID4 = ROC.TypeID4
WHERE
INV.Slot BETWEEN 0 AND 13
AND INV.Slot != 8
AND AQ.ReqLevel1 <= #Data2
AND INV.CharID = #CharID
ORDER BY AQ.ReqLevel1 DESC
Basically my query should work this way if ORDER BY clause is usable inside an update statement, but it doesn't. Is there something I can do which should solve this?
Thanks a lot in advance.
You need to determine the exact row to update for each TypeID3 / TypeID4 combination, and you can't do that in the outer query. You may need to add additional ORDER BY clauses here to break ties. You may also want to specify only a subset of columns if you have an index that covers the columns in _AEQItems used to search and the columns you're updating.
;WITH AQ AS
(
SELECT *, rn = ROW_NUMBER() OVER
(PARTITION BY TypeID3, TypeID4 ORDER BY ReqLevel1 DESC)
FROM _AEQItems
)
UPDATE I
SET RefItemID = AQ.ID,
MagParamNum = AQ.MagParamNum
FROM SRO_VT_SHARD.._Items I
JOIN SRO_VT_SHARD.._Inventory INV ON INV.ItemID = I.ID64
JOIN SRO_VT_SHARD.._RefObjCommon ROC ON ROC.ID = I.RefItemID
JOIN AQ ON AQ.TypeID3 = ROC.TypeID3 AND AQ.TypeID4 = ROC.TypeID4
WHERE AQ.rn = 1
AND INV.Slot BETWEEN 0 AND 13
AND INV.Slot!=8
AND AQ.ReqLevel1 <= #Data2
AND INV.CharID = #CharID;
Use a subquery:
UPDATE I
SET RefItemID=AQ.ID,I.MagParamNum=AQ.MagParamNum
FROM SRO_VT_SHARD.._Items I
JOIN SRO_VT_SHARD.._Inventory INV ON INV.ItemID=I.ID64
JOIN SRO_VT_SHARD.._RefObjCommon ROC ON ROC.ID=I.RefItemID
JOIN (SELECT TypeID3, TypeID4, MAX(ReqLevel1) AS ReqLevel1 FROM _AEQItems GROUP BY TypeID3, TypeID4) AQ
ON AQ.TypeID3=ROC.TypeID3
AND AQ.TypeID4=ROC.TypeID4
WHERE INV.Slot BETWEEN 0 AND 13 AND INV.Slot!=8 AND AQ.ReqLevel1<=#Data2 AND INV.CharID=#CharID

Conversion failed when converting the varchar value 'RN' to data type int

Im getting a conversion error when using the rownumber function on sql-server. I know plenty of similar threads have been posted but ive looked at them and they have different issues.
Conversion failed when converting the varchar value 'RN' to data type int.
It doesnt tell me where the problem is occuring. Does anyone have an idea of where it could be going wrong apart from the rownumber function?
This CTE is getting a previous transaction
, PRETRANSACTIONS AS (
SELECT DISTINCT
CONT.POH_ID AS POH_ID
,CONT.POH_POLICYNUMBER AS Contract_Number
,row_number() over (
partition by CONT.POH_ID
order by TRANS.txh_effectivedate desc
) AS 'RN'
,TXN_STAT.Txs_DESCRIPTION_I AS Transaction_Status_2
,TRANS.txh_effectivedate AS Transaction_Date_2
,TXN_DES.Txt_DESCRIPTION_I AS Transaction_Type_2
,TRX_RES.TRE_AMTPROCESSED AS Transaction_Amount_2
From Se2FAST.dbo.Cm_Opt_Poh_PolicyHdr_S CONT
JOIN BASE BASE
ON BASE.Poh_ID = CONT.POH_ID
INNER JOIN Se2FAST.dbo.Cm_Opt_Pch_PolicyCovHdr_S policyCov
ON CONT.Poh_ID = policyCov.Pch_POLICYHDRID
AND policycov.pch_sequence = 1
INNER JOIN [dbo].[Cm_Sys_Pst_PolicyStatus_I] PST
ON PST.Pst_ID_I = CONT.Poh_Status
LEFT JOIN se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRANS
ON TRANS.TXH_POLICYHDRID = CONT.POH_ID
AND TRANS.txh_effectivedate < ( SELECT TOP 1 TRAN1.txh_effectivedate
FROM se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRAN1
WHERE TRAN1.TXH_POLICYHDRID = CONT.POH_ID
ORDER BY txh_effectivedate DESC)
LEFT JOIN se2Fast.dbo.Cm_Opt_Tre_TrxRes_S AS TRX_RES
ON TRANS.Txh_ID = TRX_RES.Tre_TRXHDRID
LEFT JOIN se2Fast.dbo.Cm_Sys_Txt_TrxType_I TXN_DES
ON TRANS.Txh_TRXTYPEID = TXN_DES.Txt_ID_I
--AND TXN_DES.Txt_DESCRIPTION_I NOT IN (
--'Anniversary','Monthiversary','Quarterversary','Calendar Year End')
--AND TXN_DES.Txt_DESCRIPTION_I IS NOT NULL
LEFT JOIN se2Fast.dbo.Cm_Sys_Txs_TrxStatus_I TXN_STAT
ON Trans.Txh_TRXSTATUS = TXN_STAT.Txs_ID_I
AND TXN_STAT.Txs_DESCRIPTION_I = 'Completed'
WHERE 'RN' = 2
)
WHERE 'RN' = 2 is comparing two values, the string 'RN' and the integer 2. When SQL Server parses the expression, it is attempting to convert the literal value 'RN' to a numeric value to perform the integer comparison. Obviously, RN cannot be converted to a numeric value so you are getting an error.
In SQL Server, aliases are materialized after the WHERE/GROUP/HAVING clauses, but before the ORDER BY clause. This means you can't use the alias within the filter of the query it was assigned. You need to generate your column alias in a subquery before you can use it in a comparison.
It looks like you've mixed up your query. You've started as CTE named 'PRETRANSACTIONS', but then you've tried to alias it as a column after the closing parenthesis, AS 'RN'. A CTE must be referenced in the FROM before you can use the columns in the SELECT. If this is just a column expression, get rid of 'PRETRANSACTIONS AS' at the beginning.
WITH PRETRANSACTIONS AS (
SELECT DISTINCT
CONT.POH_ID AS POH_ID
,CONT.POH_POLICYNUMBER AS Contract_Number
,row_number() over (
partition by CONT.POH_ID
order by TRANS.txh_effectivedate desc)
AS RN)
SELECT RN,
TXN_STAT.Txs_DESCRIPTION_I AS Transaction_Status_2
,TRANS.txh_effectivedate AS Transaction_Date_2
,TXN_DES.Txt_DESCRIPTION_I AS Transaction_Type_2
,TRX_RES.TRE_AMTPROCESSED AS Transaction_Amount_2
From Se2FAST.dbo.Cm_Opt_Poh_PolicyHdr_S CONT
JOIN BASE BASE
ON BASE.Poh_ID = CONT.POH_ID
JOIN PRETRANSACTIONS
ON BASE.POH_ID = PRETRANSACTIONS.POH_ID
INNER JOIN Se2FAST.dbo.Cm_Opt_Pch_PolicyCovHdr_S policyCov
ON CONT.Poh_ID = policyCov.Pch_POLICYHDRID
AND policycov.pch_sequence = 1
INNER JOIN [dbo].[Cm_Sys_Pst_PolicyStatus_I] PST
ON PST.Pst_ID_I = CONT.Poh_Status
LEFT JOIN se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRANS
ON TRANS.TXH_POLICYHDRID = CONT.POH_ID
AND TRANS.txh_effectivedate < ( SELECT TOP 1 TRAN1.txh_effectivedate
FROM se2Fast.DBO.CM_OPT_TXH_TRXHDR_S TRAN1
WHERE TRAN1.TXH_POLICYHDRID = CONT.POH_ID
ORDER BY txh_effectivedate DESC)
LEFT JOIN se2Fast.dbo.Cm_Opt_Tre_TrxRes_S AS TRX_RES
ON TRANS.Txh_ID = TRX_RES.Tre_TRXHDRID
LEFT JOIN se2Fast.dbo.Cm_Sys_Txt_TrxType_I TXN_DES
ON TRANS.Txh_TRXTYPEID = TXN_DES.Txt_ID_I
--AND TXN_DES.Txt_DESCRIPTION_I NOT IN (
--'Anniversary','Monthiversary','Quarterversary','Calendar Year End')
--AND TXN_DES.Txt_DESCRIPTION_I IS NOT NULL
LEFT JOIN se2Fast.dbo.Cm_Sys_Txs_TrxStatus_I TXN_STAT
ON Trans.Txh_TRXSTATUS = TXN_STAT.Txs_ID_I
AND TXN_STAT.Txs_DESCRIPTION_I = 'Completed'
WHERE PRETRANSACTIONS.RN = 2
On a separate note, never use DISTINCT in the same set as ROW_NUMBER. ROW_NUMBER generates a unique number for every row, therefore every row is distinct. All that will do is add sorting overhead without eliminating any rows. You can use RANK or DENSE_RANK instead.
dont use 'RN', just RN without quotes.
You are getting this error because you are comparing the Text value 'RN' with an Integer value 2 in the where clause. But since 'RN' is a column and you want to return all the files that have a value 2 in the field 'RN' instead of
WHERE **'RN'** = 2
just type
WHERE RN = 2
RN without quotes as it is the name of the column.

SQL mutliple count

Could you explain how I get this particular table result?
My 4 queries to individually get each column separately are also below.
I am not sure on method here do I nest the last 3 queries into the first or do I use a union between the queries.
Bearing in mind that the information in each one doesn't really match I assume Union or Union All isn't going to be useful.
Would a derived table be a better method. Sorry my SQL skills are fairly basic.
I need to also retain the ability to 'tweak' the where clauses as my admin decides to exclude certain records later (you IT folks will be used to that!)
Some the ability to alter the where clauses would be good in a solution.
Just to make it more annoying for ya ;-)
Query table would need to look a little like this
Company Department Total_B Total_R Total_Ret RushJobs
ACME LSD 2 100 24 3
The four queries (that work separately to get each column above are here ( I have left in the respective Group By and where clauses incidentally I_Department does map to just Department in the case of 2nd query.
-- Total B count query from B
Select Company,Department, count(*) as Total_B from B
Group by Company,Department
Order BY Company;
--Select h count from h table
Select count(*) as Total_R, I_Department from H
where L ='re-box'
Group By IDepartment
-- Select r count
Select Company,Department,Count (B_Number) AS Total_Ret
from P Inner Join B ON P.Record_Number = B.B_Number
where P.Request_Date > = 'SOMEDATE' and P.Request_Date < = 'SOMEDATERANGE'
Group By Company,Department
-- Select Rush Jobs
Select Company,Department,Count (*) as RushJobs
from Res
Inner Join B on Res.Item_Number = B.B_Number
where Res.Setup_Date >= 'Somedate' and Res.Setup_Date<= 'somedaterange'
and Res.Res_Priority = '1'
Group By Company,Department
So final table
<table><TBODY>
<TR>
<TH>Company</TH>
<TH>Department</TH>
<TH>Total_B</TH>
<TH>Total_R </TH>
<TH>Total_Ret</TH>
<TH>RushJobs</TH></TR>
<TR>
<TD>ACME</TD>
<TD>LSD</TD>
<TD>100</TD>
<TD>2</TD>
<TD>4</TD>
<TD>1</TD></TR></TBODY></table>
One approach would be to use a Common table expression (CTE) aka with statement..
This allows each query to continue to be independent allowing you to easily twerk (I was going to correct that typo but it was just too funny) the where clauses for each and combines the results in the end returning 1 record with 4 columns.
-- Total B count query from B
With B as (
Select Company,Department, count(*) as Total_B from B
Group by Company,Department
Order BY Company),
H as (
--Select h count from h table
Select count(*) as Total_R, I_Department from H
where L ='re-box'
Group By IDepartment),
R as (-- Select r count
Select Company,Department,Count (B_Number) AS Total_Ret
from P Inner Join B ON P.Record_Number = B.B_Number
where P.Request_Date > = 'SOMEDATE' and P.Request_Date < = 'SOMEDATERANGE'
Group By Company,Department),
RushJobs as (-- Select Rush Jobs
Select Company,Department,Count (*) as RushJobs
from Res
Inner Join B on Res.Item_Number = B.B_Number
where Res.Setup_Date >= 'Somedate' and Res.Setup_Date<= 'somedaterange'
and Res.Res_Priority = '1'
Group By Company,Department)
SELECT coalesce(B.Company, R.Company, RJ.Company)
, coalesce(B.Department,R.Department, Rj.Department)
, B.Total_B, H.Total_R, R.Total_Ret, RJ.RushJobs
FROM
FULL OUTER JOIN H
on B.Company = H.Company
FULL OUTER JOIN R
on B.company = R.Company
and B.Department = R.Department
FULL OUTER JOIN RushJobs RJ
on H.company = RJ.Company
and H.Department = RJ.Department

TSQL - Return recent date

Having issues getting a dataset to return with one date per client in the query.
Requirements:
Must have the recent date of transaction per client list for user
Will need have the capability to run through EXEC
Current Query:
SELECT
c.client_uno
, c.client_code
, c.client_name
, c.open_date
into #AttyClnt
from hbm_client c
join hbm_persnl p on c.resp_empl_uno = p.empl_uno
where p.login = #login
and c.status_code = 'C'
select
ba.payr_client_uno as client_uno
, max(ba.tran_date) as tran_date
from blt_bill_amt ba
left outer join #AttyClnt ac on ba.payr_client_uno = ac.client_uno
where ba.tran_type IN ('RA', 'CR')
group by ba.payr_client_uno
Currently, this query will produce at least 1 row per client with a date, the problem is that there are some clients that will have between 2 and 10 dates associated with them bloating the return table to about 30,000 row instead of an idealistic 246 rows or less.
When i try doing max(tran_uno) to get the most recent transaction number, i get the same result, some have 1 value and others have multiple values.
The bigger picture has 4 other queries being performed doing other parts, i have only included the parts that pertain to the question.
Edit (2011-10-14 # 1:45PM):
select
ba.payr_client_uno as client_uno
, max(ba.row_uno) as row_uno
into #Bills
from blt_bill_amt ba
inner join hbm_matter m on ba.matter_uno = m.matter_uno
inner join hbm_client c on m.client_uno = c.client_uno
inner join hbm_persnl p on c.resp_empl_uno = p.empl_uno
where p.login = #login
and c.status_code = 'C'
and ba.tran_type in ('CR', 'RA')
group by ba.payr_client_uno
order by ba.payr_client_uno
--Obtain list of Transaction Date and Amount for the Transaction
select
b.client_uno
, ba.tran_date
, ba.tc_total_amt
from blt_bill_amt ba
inner join #Bills b on ba.row_uno = b.row_uno
Not quite sure what was going on but seems the Temp Tables were not acting right at all. Ideally i would have 246 rows of data, but with the previous query syntax it would produce from 400-5000 rows of data, obviously duplications on data.
I think you can use ranking to achieve what you want:
WITH ranked AS (
SELECT
client_uno = ba.payr_client_uno,
ba.tran_date,
be.tc_total_amt,
rnk = ROW_NUMBER() OVER (
PARTITION BY ba.payr_client_uno
ORDER BY ba.tran_uno DESC
)
FROM blt_bill_amt ba
INNER JOIN hbm_matter m ON ba.matter_uno = m.matter_uno
INNER JOIN hbm_client c ON m.client_uno = c.client_uno
INNER JOIN hbm_persnl p ON c.resp_empl_uno = p.empl_uno
WHERE p.login = #login
AND c.status_code = 'C'
AND ba.tran_type IN ('CR', 'RA')
)
SELECT
client_uno,
tran_date,
tc_total_amt
FROM ranked
WHERE rnk = 1
ORDER BY client_uno
Useful reading:
Ranking Functions (Transact-SQL)
ROW_NUMBER (Transact-SQL)
WITH common_table_expression (Transact-SQL)
Using Common Table Expressions

Resources