SELECT MAX Date T-SQL Subquery - sql

I am attempting to SELECT rows from a table using a query like this
SELECT pminf_member, pminf_schmem
, pminf_date, pminf_fund
, pminf_cont, pminf_rate
, pminf_matrix
FROM pe_minvf
WHERE (pminf_member = 4380)
AND (pminf_schmem = 'M')
AND (pminf_date <= '03/30/2011')
AND (pminf_date =
(SELECT MAX(pminf_date) AS Expr1
FROM pe_minvf AS pe_minvf_1
WHERE (pminf_member = 4380)
)
)
AND (pminf_fund = 'LIFESTYLE')
What I should be getting from my subquery (I think) is a date of '01/01/2011' but when I run my query I am getting no results back.
If I replace the subquery with the hardcoded date I get the correct rows returned. For example
SELECT pminf_member, pminf_schmem
, pminf_date, pminf_fund
, pminf_cont, pminf_rate
, pminf_matrix
FROM pe_minvf
WHERE (pminf_member = 4380)
AND (pminf_schmem = 'M')
AND (pminf_date <= '03/30/2011')
AND (pminf_date = '01/01/2011')
AND (pminf_fund = 'LIFESTYLE')
This query returns the correct results.
Any ideas why the subquery is not returning the max date or if it is, why am I getting no rows back?
Thanks,
Tristan

You filter on different conditions in your queries.
It's pminf_fund = 'LIFESTYLE' in the subquery but pminf_schmem = 'M' in the outer query.
Also, you limit the date in the outer query and don't do it in the subquery.
If you just need the most recent record up to '03/30/2011', use this:
SELECT TOP 1
pminf_member, pminf_schmem, pminf_date, pminf_fund, pminf_cont, pminf_rate, pminf_matrix
FROM pe_minvf
WHERE pminf_member = 4380
AND pminf_schmem = 'M'
AND pminf_fund = 'LIFESTYLE'
AND pminf_date <= '03/30/2011'
ORDER BY
pminf_date DESC

SELECT pminf_member, pminf_schmem
, pminf_date, pminf_fund
, pminf_cont, pminf_rate
, pminf_matrix
FROM pe_minvf
WHERE (pminf_member = 4380)
AND (pminf_schmem = 'M')
AND (pminf_date =
(SELECT MAX(pminf_date) AS Expr1
FROM pe_minvf AS p
WHERE (p.pminf_member = 4380) AND
p.pminf_date <= '03/30/2011'
)
)
AND (pminf_fund = 'LIFESTYLE')

The query:
SELECT MAX(pminf_date) AS Expr
FROM pe_minvf AS pe_minvf_1
WHERE (pminf_member = 4380)
;
returns '01/01/2011' or something else?
Perhaps you want the same conditions on the subquery as in th emain query:
SELECT MAX(pminf_date) AS Expr
FROM pe_minvf AS pe_minvf_1
WHERE (pminf_member = 4380)
AND (pminf_schmem = 'M')

use a subquery to limit rows returned instead of the where clause. Use this as the subquery:
(SELECT MAX(pminf_date) AS Expr1
FROM pe_minvf AS pe_minvf_1
WHERE (pminf_member = 4380)
Keep the query basically the same...
Select same_fields_as you_did_before
from pe_minvf
inner join
(SELECT MAX(pminf_date) AS Maxdate, tablekey
FROM pe_minvf AS pe_minvf_1
WHERE pminf_member = 4380) a on a.tablekey = pe_minvf.table_key
where same_where_clause_you_had
Make sense? I wasn't sure what your table_key was on pe_minvf...you'll have to insert that yourself. I find using subqueires adn inner joining to them is a more effective way of limiting rows then having a subquery in your where clause

Twelfth!
Thanks for the proper syntax... I used it to resolve my similar problem de-jur (of-the-day)
Unless I am wrong, what I have below will work.. If it doesn't I will fix it here...
In the example below the data fields name have been cleansed but the syntax worked very fast.
By the way, there are 20,480 distinct device_id
declare
#BegDate varchar(20)=(select cast(CONVERT(VARCHAR(20), getdate()-2,101) as varchar(20)) + ' 10:59:59 PM')
,#EndDate varchar(20)=(select cast(CONVERT(VARCHAR(20), getdate()-0,101) as varchar(20)) + ' 11:00:00 PM')
select f1.ABC_ConfigProcStatusID,f1.DeviceID,f1.DBfilename ,f1.LastUpdatedDate
from dbo.ABC_ConfigProcStatus f1
inner join
(select distinct DeviceID,max(LastUpdatedDate) as max_DeviceIDdte
from dbo.ABC_ConfigProcStatus
where [Status]=2
and DeviceID not in(select ExclusionDeviceIDs from ABC_ConfigDeviceIDExclusionList)
group by DeviceID) f2
on f2.max_DeviceIDdte = f1.LastUpdatedDate
where [Status]=2
and f2.DeviceID = f1.DeviceID
and f1.DeviceID not in(select ExclusionDeviceIDs from ABC_ConfigDeviceIDExclusionList)
and LastUpdatedDate between #BegDate and #EndDate
and left(upper(f1.DeviceID),3) in ('XYZ','ZKO')
order by f1.LastUpdatedDate

Related

SQL count(*) with having

I have this query on oracle.
SELECT CBG.refs, CBG.cuo, CBG.date, CBG.nber, CG.date, CBG.conso,
(SELECT COUNT(*)
FROM MAD.VIN CBV
WHERE CBV.CUO = CBG.CUO AND
CBV.NBER = CBG.NBER AND
CBV.DATE = CBG.DATE AND
CBV.REFS = CBG.REFS
GROUP BY CUO , DATE , NBER , REFS ) AS COUNTS ,
CBG.CONSO_CONCESS AS CONCESS
FROM MAD.GEN CBG, MAD.CAR_GEN CG
WHERE CBG.cuo = CG.cuo AND
CBG.CONSO_DATE IS NOT NULL AND
CBG.date = CG.date AND
CBG.nber = CG.nber
HAVING COUNTS > 0;
when i run this sql query it gives me an error that says: invalid identifier counts.
How do we get results only if count is greater than a given parameter?
Thanks.
Unlike in MySQL, in Oracle we cannot refer to an alias in the HAVING clause (aliases can only be referenced in the ORDER BY clause). One workaround would be to put your current logic into a CTE and then filter it.
WITH cte AS (
SELECT CBG.refs, CBG.cuo, CBG.date AS cbg_date, CBG.nber, CG.date AS cg_date,
CBG.conso,
(SELECT COUNT(*)
FROM MAD.VIN CBV
WHERE CBV.CUO = CBG.CUO AND
CBV.NBER = CBG.NBER AND
CBV.DATE = CBG.DATE AND
CBV.REFS = CBG.REFS
GROUP BY CUO, DATE, NBER, REFS) AS COUNTS,
CBG.CONSO_CONCESS AS CONCESS
FROM MAD.GEN CBG
INNER JOIN MAD.CAR_GEN CG
ON CBG.cuo = CG.cuo AND
CBG.date = CG.date AND
CBG.nber = CG.nber
WHERE CBG.CONSO_DATE IS NOT NULL
)
SELECT refs, cuo, cbg_date, nber, cg_date, conso, COUNTS, CONCESS
FROM cte
WHERE COUNTS > 0;

A problem in returning a table with Null On it

i want my function to return a A table with some values
I must fix something in the update but i don't know what
this is the function FngetTableH BELOW
ALTER FUNCTION [dbo].[FnGetTableH]
(
#Date DateTime
)
RETURNS #Listeab_ Table(CLOSING_PRICE money,IdValeur int)
AS
BEGIN
Insert #Listeab_
( CLOSING_PRICE ,IdValeur)
select Distinct 0 , IdValeur
From Historique
Update #Listeab_
Set CLOSING_PRICE = (Select CLOSING_PRICE
from Historique H
inner join (Select MAX(#Date) As DATEDU,IdValeur FROM Historique
where
DATE_NEGO<= #Date
group by IdValeur ) L2
on
H.DATE_NEGO=L2.DATEDU
and
H.IdValeur=L2.IdValeur
)
return
END
when i Execute this code
declare #Date date = '10/09/2013'
---select*from FnGetTableH(#Date)
select C.IdClient,H.IdValeur,C.RaisonSocial,SUM( case I.sens
WHEN 'c' then + I.Qantite
WHEN'd' then - I.Qantite
END) as 'Solde', H.closing_price
from Imputations I
Inner join FnGetTableH(#Date) H
on H.IdValeur=I.IdValeur
Inner join Clients C
on C.IdClient=I.IdClient
where I.DateImputation=#Date
group by C.IdClient,RaisonSocial,H.closing_price,H.IdValeur
Order by IdClient asc
i get
Msg 512, Niveau 16, État 1, Ligne 4
La sous-requête a retourné plusieurs valeurs. Cela n'est pas autorisé quand la sous-requête suit =, !=, <, <= , >, >= ou quand elle est utilisée en tant qu'expression.
L'instruction a été arrêtée.
In your innermost query I think MAX(#Date) should be MAX(DATE_NEGO), which might explain why the closing price query is returning multiple results.
There is still the possibility of multiple results, so you might need to account for that You could select max(closing_price) if it doesn't matter which, though I suspect it might, in which case you need to do some ordering to select the correct price to use.
EDIT: Try this:
ALTER FUNCTION [dbo].[FnGetTableH]
(
#Date DATETIME
)
RETURNS #Listeab_ TABLE
(
CLOSING_PRICE MONEY,
IdValeur INT
)
AS
BEGIN
WITH prices AS
(
SELECT IdValeur,
CLOSING_PRICE,
ROW_NUMBER() OVER (PARTITION BY IdValuer ORDER BY DATE_NEGO DESC) rn
FROM Historique
WHERE DATE_NEGO <= #Date
)
INSERT #Listeab_(CLOSING_PRICE, IdValeur)
SELECT DISTINCT ISNULL(p.CLOSING_PRICE, 0),
h.IdValeur
FROM Historique h
LEFT OUTER JOIN prices p ON h.IdValeur = p.IdValeur
AND p.rn = 1
RETURN;
END;
your query "Select CLOSING_PRICE from Historique H inner..." may be returning more than 1 value.
Use top to select 1 record. May be it will solve your error.
select Distinct 0 , IdValeur
From Historique
Update #Listeab_
Set CLOSING_PRICE = (Select Top 1 CLOSING_PRICE
from Historique H
inner join (Select MAX(#Date) As DATEDU,IdValeur FROM Historique
where
DATE_NEGO<= #Date
group by IdValeur ) L2
on
H.DATE_NEGO=L2.DATEDU and H.IdValeur=L2.IdValeur
)

Should a subquery on a join use tables from an outer query in the where clause?

I need to add a subquery to a join, because one payment can have more than one allotment, so I only need to account for the first match (where rownum = 1).
However, I'm not sure if adding pmt from the outer query to the subquery on the allotment join is best.
Should I be doing this differently in the event of performance hits, etc.. ?
SELECT
pmt.payment_uid,
alt.allotment_uid,
FROM
payment pmt
/* HERE: is the reference to pmt.pay_key and pmt.client_id
incorrect in the below subquery? */
INNER JOIN allotment alc ON alt.allotment_uid = (
SELECT
allotment_uid
FROM
allotment
WHERE
pay_key = pmt.pay_key
AND
pay_code = 'xyz'
AND
deleted = 'N'
AND
client_id = pmt.client_id
AND
ROWNUM = 1
)
WHERE
AND
pmt.deleted = 'N'
AND
pmt.date_paid >= TO_DATE('2017-07-01')
AND
pmt.date_paid < TO_DATE('2017-10-01') + 1;
It's difficult to identify the performance issue in your query without seeing an explain plan output. You query does seem to do an additional SELECT on the allotment for every record from the main query.
Here is a version which doesn't use correlated sub query. Obviously I haven't been able to test it. It does a simple join in and then filters all records except one of the allotments. Hope this helps.
WITH v_payment
AS
(
SELECT
pmt.payment_uid,
alt.allotment_uid,
ROW_NUMBER () OVER(PARTITION BY allotment_id) r_num
FROM
payment pmt JOIN allotment alt
ON (pmt.pay_key = alt.pay_key AND
pmt.client_id = alt.client_id)
WHERE pmt.deleted = 'N' AND
pmt.date_paid >= TO_DATE('2017-07-01') AND
pmt.date_paid < TO_DATE('2017-10-01') + 1 AND
alt.pay_code = 'xyz' AND
alt.deleted = 'N'
)
SELECT payment_uid,
allotment_uid
FROM v_payment
WHERE r_num = 1;
Let's know how this performs!
You can phrase the query that way. I would be more likely to do:
SELECT . . .
FROM payment p INNER JOIN
(SELECT a.*,
ROW_NUMBER() OVER (PARTITION BY pay_key, client_id
ORDER BY allotment_uid
) as seqnum
FROM allotment a
WHERE pay_code = 'xyz' AND deleted = 'N'
) a
ON a.pay_key = p.pay_key AND a.client_id = p.client_id AND
seqnum = 1
WHERE p.deleted = 'N' AND
p.date_paid >= DATE '2017-07-01' AND
p.date_paid < (DATE '2017-10-01') + 1;

Subquery returned more than 1 value. My WHERE clause needs to remove SELECT statements

I have a SQL Stored Procedure that is giving issues. I am aware that it is most likely the SELECT statements in the WHERE clause that are returning multiple values. I commented out the WHERE and results were returned.
My question is how do I modify the statement so that I can still filter on those conditions?
Stored Proc code:
SELECT
REPORT_SPOOL.ID,
REPORT_SPOOL.REPORT_SPOOL_TYPE_ID,
REPORT_SPOOL.FUND_ID,
REPORT_SPOOL.PERF_ENTITY_ID,
REPORT_SPOOL.REPORT_GUID,
REPORT_SPOOL.REPORT_TEMPLATE_GUID,
PERF_ENTITY.CODE AS PERF_ENTITY_CODE,
PERF_ENTITY.NAME AS PERF_ENTITY_NAME,
FUND.CODE AS FUND_CODE,
FUND.NAME AS FUND_NAME,
REPORT.CODE AS REPORT_CODE,
REPORT.NAME AS REPORT_NAME,
REPORT_TEMPLATE.CODE AS REPORT_TEMPLATE_CODE,
REPORT_TEMPLATE.NAME AS REPORT_TEMPLATE_NAME,
FUND.ACCOUNTING_START AS START_DATE,
FUND.ACCOUNTING_END AS END_DATE
FROM
PERF_ENTITY
RIGHT OUTER JOIN
REPORT
INNER JOIN
REPORT_SPOOL
ON REPORT.GUID = REPORT_SPOOL.REPORT_GUID
INNER JOIN
REPORT_TEMPLATE
ON REPORT_SPOOL.REPORT_TEMPLATE_GUID = REPORT_TEMPLATE.GUID
ON PERF_ENTITY.ID = REPORT_SPOOL.PERF_ENTITY_ID
LEFT OUTER JOIN
FUND
ON REPORT_SPOOL.FUND_ID = FUND.ID
WHERE
(END_DATE IS NULL OR END_DATE > #REPORT_DATE)
AND
REPORT_SPOOL.FUND_ID = (SELECT FUND_ID FROM FUND_HLD WHERE [DATE] = #REPORT_DATE)
AND
REPORT_SPOOL.FUND_ID = (SELECT FUND_ID FROM FUND_TRD_LINE_VIEW WHERE [DATE] >= (SELECT DATEFROMPARTS(YEAR(#REPORT_DATE),MONTH(#REPORT_DATE),1)) AND [DATE] <= #REPORT_DATE)
Those last 2 SELECTS are the issue
Replace = with in in the sub query:
REPORT_SPOOL.FUND_ID in (SELECT FUND_ID FROM FUND_HLD WHERE [DATE] = #REPORT_DATE)
AND
REPORT_SPOOL.FUND_ID in (SELECT FUND_ID FROM FUND_TRD_LINE_VIEW WHERE [DATE] >= (SELECT DATEFROMPARTS(YEAR(#REPORT_DATE),MONTH(#REPORT_DATE),1)) AND [DATE] <= #REPORT_DATE)

SQL Show dates without transactions as value = 0

I'm doing a weight reporting and I have a problem. I use this query to know the enters of weight in our warehouse, but when there are no transactions in a date this date doesn't appears in the results.
SELECT erp.MKPF.BUDAT AS Data,
Sum( erp.MSEG.MENGE * erp.MARM.BRGEW ) as pes
From erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MKPF.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112) -1
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
GROUP BY erp.MKPF.BUDAT*
Now the results are like this:
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120723 9999999.7777
And i need this
Data PES
20120720 9999999.9999
20120721 9999999.8888
20120722 0
20120723 999999.7777
Can somebody help me?
Use a table or a view to generate the date range of interest and let this drive the query. Then you outer join your results to this view. This can be done dynamically in the query. For example, in Oracle, you can use "connect by" to generate a series:
create table my_summary(the_day date, pes number);
insert into my_summary values(to_date('20120720', 'yyyymmdd'), 9999999.9999);
insert into my_summary values(to_date('20120721', 'yyyymmdd'), 9999999.8888);
insert into my_summary values(to_date('20120723', 'yyyymmdd'), 9999999.7777);
SELECT d.the_day, NVL(s.pes, 0) AS pes
FROM ( SELECT to_date('20120720', 'yyyymmdd') + level -1 AS the_day
FROM dual CONNECT BY level <= 4) d
LEFT OUTER JOIN my_summary s ON (d.the_day = s.the_day)
ORDER BY 1
THE_DAY PES
--------- ---
20-JUL-12 9999999.9999
21-JUL-12 9999999.8888
22-JUL-12 0
23-JUL-12 9999999.7777
Other rdbms have other methods to generate a series. This will require you to know the start date you want, and the number of records (in the example above 20120720 and 4).
Thanks to all, finally I did this and it works
SELECT
c.BUDAT AS DATA,
CASE When SAP.pes Is Null then '0'
ELSE SAP.pes
END
From
erp.YSD_CALENDAR as c LEFT JOIN
(SELECT
erp.MKPF.BUDAT,
Sum(
erp.MSEG.MENGE
* erp.MARM.BRGEW ) as pes
FROM
erp.MKPF
INNER Join erp.MSEG on erp.MKPF.MANDT = erp.MSEG.MANDT and erp.MKPF.MBLNR = erp.MSEG.MBLNR
INNER Join erp.MARM on erp.MSEG.MANDT = erp.MARM.MANDT and erp.MSEG.MATNR = erp.MARM.MATNR And erp.MSEG.MEINS = erp.MARM.MEINH
INNER JOIN erp.MARA on erp.MSEG.MANDT = erp.MARA.MANDT and erp.MSEG.MATNR = erp.MARA.MATNR
WHERE
erp.MKPF.MANDT = '100'
and erp.MKPF.BUDAT >= '20120720'
and erp.MSEG.LGORT in ('1001','1069')
and erp.MSEG.BWART In ('101','102','311','312')
and erp.MSEG.WERKS = '1001'
and erp.MARA.MTART in ('Z001','Z010','Z002','Z02E')
and erp.MSEG.SHKZG = 'S'
GROUP BY erp.MKPF.BUDAT
) SAP ON SAP.BUDAT = c.BUDAT
WHERE
c.BUDAT >= '20120720'
and c.BUDAT <= CONVERT(VARCHAR(8), GETDATE(), 112)
GROUP BY c.BUDAT, SAP.pes
ORDER BY c.BUDAT