Multiple query date range - sql

I have multiple queries that I run each day, Is there a way to set a date range for multiple selects rather than enter the date in each select.I use oracle sql developer to run these.
here is an example of just three but there are around a dozen queries:
select count(*)"Tall ord"
from cr_ordpar
inner join cr_palhis on cr_palhis.pikref = cr_ordpar.pikref
inner join CR_LODHED_DESP on cr_lodhed_desp.ilodno = cr_ordpar.ILODNO
where cr_palhis.hstdat between '24-nov-15 07:00' and '25-nov-15 07:00:00'
and hststs_str = 'Pallet Output From Racking'
and cr_palhis.palhgt = '2700'
order by cr_lodhed_desp.lodref;
select count(*)"Tall del"
from cr_palhis
where cr_palhis.hstdat between '24-nov-15 07:00' and '25-nov-15 07:00:00'
and hststs_str = 'Pallet Deleted'
and cr_palhis.palhgt = 2700
and cr_palhis.rakblk <> 510;
select count(*)"Tall ind"
from cr_palhis
where cr_palhis.hstdat between '24-nov-15 07:00' and '25-nov-15 07:00:00'
and hststs_str = 'Pallet Indexed'
and cr_palhis.PALHGT = '2700';

There are multiple issues with your DATE.
Firstly, '24-nov-15 07:00' is not a DATE, it is a string. You must always use TO_DATE to explicitly convert a literal into DATE. Also, remember TO_DATE is NLS dependent if you do not mention the NLS_DATE_LANGUAGE. NOV is not the same in other languages.
YY format was long ago recongnised as Y2K bug and the world already saw the efforts to get rid off it. Either mention complete YYYY or use RR format, but understand it before implementing.
TO_DATE('24-nov-2015 07:00','dd-mon-yyyy hh24:mi','nls_date_language=ENGLISH')
You could use GROUP BY clause to get the different counts in a single query. Given that all the conditions remain same.
SELECT hststs_str,
COUNT(*) cnt
FROM cr_ordpar
INNER JOIN cr_palhis
ON cr_palhis.pikref = cr_ordpar.pikref
INNER JOIN CR_LODHED_DESP
ON cr_lodhed_desp.ilodno = cr_ordpar.ILODNO
WHERE cr_palhis.hstdat
BETWEEN TO_DATE('24-nov-2015 07:00','dd-mon-yyyy hh24:mi','nls_date_language=ENGLISH')
AND TO_DATE('25-nov-2015 07:00','dd-mon-yyyy hh24:mi','nls_date_language=ENGLISH')
AND hststs_str IN( 'Pallet Output From Racking',
'Pallet Deleted',
'Pallet Indexed'
)
AND cr_palhis.palhgt = '2700'
AND cr_palhis.rakblk <> 510
GROUP BY hststs_str
ORDER BY cnt;

Related

sql with group by and range of dates

I have a query which uses max aggregate function to calculate reset date for a particular selection date.There is a table vp_Accrual which have effectivedate field.selection date is passed to effectivedate field and based on that using Max function, reset date is calculated.This Query gives result only for a particular selection date.It calculate a reset date based on selection date passed.
I want to modify it so that it will give me reset date for a range of dates
Below Query gives Output for one person for the date 1st Jan as follow.
We need to modify Query so that it will give result for multiple selection date instead of only one selection date.
I tried by adding addition #enddate field as effectivedate between #selectiondate and #enddate.
But I guess tha approach is not correct.
I want to pass range of date, such as 1st jan to 4th Jan, and it should give Output for each date as below
[Image is added as Link as i dont have enough Repuation Point][https://i.stack.imgur.com/0HSX1.jpg]
Below is the Query used.
DECLARE #selectionDate datetime
SET #selectionDate = CONVERT(nvarchar(10), DATEADD(dd, 0, CAST('01/01/2017' AS datetime)), 101)
SELECT
e.personnum,
ac.name as Accrul_Code,
#selectionDate as Selection_DATE,
CASE
WHEN MAX(va.effectivedate) IS NULL THEN CAST('1/1/1753' AS datetime)
ELSE MAX(va.effectivedate)
END AS resetdate
FROM vp_employeev42 e WITH (NOLOCK)
INNER JOIN accrualprofile ap
ON e.accrualprflname = ap.name
INNER JOIN accrualprofilemm apm
ON apm.accrualprofileid = ap.accrualprofileid
INNER JOIN accrualrule ar
ON apm.accrualruleid = ar.accrualruleid
INNER JOIN accrualcode ac
ON ac.accrualcodeid = ar.accrualcodeid
LEFT OUTER JOIN vp_accrual va
ON va.accrualcodeid = ar.accrualcodeid
AND e.personid = va.personid
AND accrualtrantype IN (3, 11)
AND va.effectivedate <= #selectionDate
WHERE
ac.NAME IN ('FT PTO','LOC','EPT - 5','PT PTO','EPT')
AND va.DISQUALIFIEDSW != 1
and e.PERSONNUM='00152'
GROUP BY e.personnum,
ac.name
Please help me with this Query
Best I can make out, you want a Cartesian join on a fake date table that will cause your results to repeat themselves over and over, but for a different set of dates each time
Something like this:
DECLARE #selectionDate datetime
DECLARE #endDate datetime
SET #selectionDate = DATEFROMPARTS(2017,1,1)
SET #endDate = DATEFROMPARTS(2017,5,1)
WITH dates ( IncDate ) AS (
SELECT #selectionDate UNION ALL
SELECT DATEADD(month,1,IncDate) FROM dates WHERE Incdate <= #endDate )
SELECT
e.personnum,
ac.name as Accrul_Code,
IncDate as Selection_DATE,
MAX(COALESCE(effectivedate, CAST('1/1/1753' AS datetime)) AS resetdate
FROM vp_employeev42 e WITH (NOLOCK)
INNER JOIN accrualprofile ap
ON e.accrualprflname = ap.name
INNER JOIN accrualprofilemm apm
ON apm.accrualprofileid = ap.accrualprofileid
INNER JOIN accrualrule ar
ON apm.accrualruleid = ar.accrualruleid
INNER JOIN accrualcode ac
ON ac.accrualcodeid = ar.accrualcodeid
CROSS JOIN dates
LEFT OUTER JOIN vp_accrual va
ON va.accrualcodeid = ar.accrualcodeid
AND e.personid = va.personid
AND accrualtrantype IN (3, 11)
AND effectivedate <= IncDate
WHERE
ac.NAME IN ('FT PTO','LOC','EPT - 5','PT PTO','EPT')
AND va.DISQUALIFIEDSW != 1
and e.PERSONNUM='00152'
GROUP BY e.personnum,
ac.name,
IncDate
A few cautions though:
This query cannot generate the results you posted, but neither can yours. There's no logic at all to your example results, where your reset date is the max date that is less than the selection date but your first of February selection date somehow chooses the tenth of Jan, yet your first of march selection date chooses the eleventh of Jan.
This is totally untested; you provided no sample data, only an image of the results, and I post from an iPad, so generating test data would be incredibly laborious, typing it all in
You mix up your dates as varchar and datetime. Please be more diligent in keeping these data types separate. Always work with dates as dates, not strings. Never store dates as string. Never rely on implicit conversions between date and string
DATEFROMPARTS came along in sqlserver 2012 I think, if your sql is older than this, use convert with a format string to turn your string into a date.. do not declare selectiondate as a varchar!

ORA-01858 error using dates

I am not a programmer by trade but I know some SQL. I just need another set of eyes on my code because I am not sure why I am getting this error.
select
count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and ci.ci_create_date in (select case when ci.ci_create_date between to_date('1/1/2016','mm/dd/yyyy') and to_date('1/31/2016','mm/dd/yyyy') then 'January'
when ci.ci_create_date between to_date('2/1/2016','mm/dd/yyyy') and to_date('2/29/2016','mm/dd/yyyy') then 'February'
when ci.ci_create_date between to_date('3/1/2016','mm/dd/yyyy') and to_date('3/31/2016','mm/dd/yyyy') then 'March'
else '' end from regmdr.contact_interaction ci group by to_char(ci.ci_create_date, 'yyyy-mm')
You are trying to compare the ci.ci_create_date date value with the string that is produced by your case statement, which is January, February, March or null. So you're effectively doing a comparison like:
ci.ci_create_date = to_date('January')
Unless your NLS_DATE_FORMAT is 'Month' and your language is English, that will get the ORA-01858. You could convert the left-hand side of that to the month name too, but without the year in either format model that would include data from January in any year; and it's better for performance to not convert the data from the table if you can avoid it.
It isn't entirely clear what you're trying to do but as the subquery has an independent view of contact_interaction with no correlation it probably isn't going to do whatever you are trying anyway.
If you're trying to count values from the first three months of this year then you can do:
select count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and ci.ci_create_date >= date '2016-01-01'
and ci.ci_create_date < date '2016-04-01'
Which will give you a single number. If you want it by month your group by was in the wrong place, and you can add
...
group by trunc(ci.ci_create_date, 'MM')
although you really need that in the select list too for the result set to make any sense - so you know which month each count belongs to.
Based on using the month names at all, perhaps you wanted those in the select list:
select to_char(trunc(ci.ci_created_date, 'MM'), 'Month') as month,
count(1) as AH
from regmdr.contact_interaction ci
...
group by trunc(ci.ci_create_date, 'MM')
... but I'm speculating even more now. Also be aware that month names are sensitive to your NLS settings, particularly NLS_DATE_LANGUAGE. You can force them to always be in English via the optional third argument to to_char() though, e.g.
select to_char(trunc(ci.ci_created_date, 'MM'), 'Month', 'NLS_DATE_LANGUAGE=ENGLISH')
...
Why not go with:
select to_char(ci.ci_create_date, 'YYYY-MM') monthyear,
count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and to_char(ci.ci_create_date, 'MON' in ('JAN', 'FEB', 'MAR')
group by to_char(ci.ci_create_date, 'yyyy-mm';
If you are only interested in the counts (without context), wrap it in an outside select statement:
select AH
from (select to_char(ci.ci_create_date, 'YYYY-MM') monthyear,
count(1) AH
from regmdr.contact_interaction ci
join regmdr.source_data sd on ci.sd_id = sd.sd_id
join regmdr.account_contact ac on ci.acct_cont_id = ac.acct_cont_id
join regmdr.account acc on ac.acc_id = acc.acc_id
where sd.sd_user_type in ('1','2')
and sd.sd_origin_reference = 'www.alliancehealth.com'
and to_char(ci.ci_create_date, 'MON') in ('JAN', 'FEB', 'MAR')
group by to_char(ci.ci_create_date, 'yyyy-mm'
);

SQL Server DATE conversion error

Here is my query:
SELECT
*
FROM
(SELECT
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE
APV.DateValue < GETDATE()
It results in the following error:
Conversion failed when converting date and/or time from character string.
If you comment out the WHERE APV.DateValue < GETDATE() clause then there is no error and I get the 300+ rows. When I enable the WHERE clause I get the error.
So you are going to tell me my data is jacked up right? Well that's what I thought, so I tried to figure out where the problem in the data was, so I started using TOP() to isolate the location. Problem was once I use the TOP() function the error went away, I only have 2000 rows of data to begin with. So I put a ridiculous TOP(99999999) on the inner SELECT and now the entire query works.
The inner SELECT returns the same number of rows with or without the TOP().
WHY???
FYI, this is SQL that works:
SELECT
*
FROM
(SELECT TOP(99999999)
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4
) AS APV
WHERE
APV.DateValue < GETDATE()
The problem that you are facing is that SQL Server can evaluate the expressions at any time during the query processing -- even before the WHERE clause gets evaluated. This can be a big benefit for performance. But, the consequence is that errors can be generated by rows not in the final result set. (This is true of divide-by-zero as well as conversion errors.)
Fortunately, SQL Server has a work-around for the conversion problem. Use try_convert():
TRY_CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
This returns NULL rather than an error if there is a problem.
The reason why some versions work and others don't is because of the order of execution. There really isn't a way to predict what does and does not work -- and it could change if the execution plan for the query changes for other reasons (such as table statistics). Hence, use try_convert().
My guess is that your date is such that APV.VALUE contains also data that cannot be converted into a date, and should be filtered out using the other criteria?
Since SQL Server can decide to limit the data first using the criteria you have given:
APV.DateValue < CONVERT( DATETIME, GETDATE(),101)
And if there is data that cannot be converted into the date, then you will get the error.
To make it more clear, this is what is being filtered:
CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
And if there is any data that cannot be converted into a date using 101 format, the filter using getdate() will fail, even if the row would not be included in the final result set for example because AP.PropertyName does not contain DATE.
Since you're using SQL Server 2012, using try_convert instead of convert should fix your problem
And why it works with top? In that case SQL Server cannot use the criteria from the outer query, because then the result might change, because it might affect the number of rows returned by top
Because number of records in the table < 999..99. And regarding the error it seems like SQL engine evaluates the WHERE clause after converting to date so you can try this:
SELECT *
FROM (
SELECT A.Name
, AP.PropertyName
, APV.Value AS [PropertyValue]
,
CASE
WHEN SDATE(APV.Value) = 1
THEN CONVERT( DATETIME, APV.VALUE, 101)
ELSE NULL
END AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP
ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV
ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND LEN( SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE APV.DateValue IS NOT NULL AND APV.DateValue < GETDATE()

Get date from substring in where clause of a sql select *EDITED*

I have a date stored within a text field with other text. Why didn't they just put this in a date field? I have no idea, but I do not have the power to change it now. Elsewhere in the code, I am doing this to get the records where this date is in a certain range. It works fine.
For Each i As InventoryItem In inventoryList
index = i.Notes.IndexOf("on {") + 4
scanned_dt = i.Notes.Substring(index, i.Notes.Length - index - 1)
If Date.Parse(scanned_dt) >= startDate And Date.Parse(scanned_dt) <= endDate Then
...
I am now trying to get a total of items for a certain date range.
This sql statement works to get the total for all dates. How can I update the Where clause to only count the items where i.Notes contains a date between startDate and endDate
Dim sql As String = "Select COUNT(inv_PartNum) from lester.inventory i join lester.vendor v on v.vendor_ID = i.vendor_ID Where v.vendor_Name = '" + vendorName + "' AND i.inv_Desc LIKE '%" + size + "%'"
*EDITED*
I came up with this sql select statement:
SELECT COUNT(i.inv_PartNum) FROM cdms.lester.inventory AS I
join CDMS.lester.vendor AS v on v.vendor_ID = i.vendor_ID Where v.vendor_Name = 'JVE-285'
AND CONVERT(DATETIME,
SUBSTRING(i.inv_Notes, CharIndex('on {', i.inv_Notes)+4, len(i.inv_Notes)-(CharIndex('on {', i.inv_Notes) + 4)
),101) BETWEEN '01-01-2011' AND '04-04-2011'
But I am getting this error:
The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.
In trying to figure it out I created the following sql select statement:
SELECT * FROM (
SELECT i.inv_Notes,
CONVERT(DATETIME,SUBSTRING(i.inv_Notes, CharIndex('on {',i.inv_Notes)+4,LEN(i.inv_Notes)-(CharIndex('on {', i.inv_Notes) + 4)),101) AS d
FROM cdms.lester.inventory AS i
join CDMS.lester.vendor AS v ON v.vendor_ID = i.vendor_ID WHERE v.vendor_Name = 'JVE-285') AS s
My inv_Notes column contains a string like "Assigned to Tool Trailer {JVE-285} on {4/8/2011}"
When I run the query as shown above, I get my inv_Notes column along with the date column. The dates all show in this format "2011-04-08 00:00:00.000" and no errors are thrown.
However as soon as I add a WHERE clause, I get the error: The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.
I've tried formatting the date every which way, but always get the error...
WHERE s.d > CONVERT(DATETIME, '2011-1-1', 101)
WHERE s.d < GetDate()
WHERE s.d > '20110101'
WHERE s.d >= '2011-01-01'
WHERE s.d >= '01-01-2011'
WHERE s.d > '01/01/2011'
EDIT
I've also tried
WHERE s.d IS NOT NULL
and get the same error. This obviously isn't working the way I think it's working b/c at the point of the WHERE, the conversion should have already successfully happened.
SOLUTION
Got this working
SELECT * FROM (
SELECT i.inv_Notes,
SUBSTRING(i.inv_Notes, CharIndex('} on {',i.inv_Notes)+6,LEN(i.inv_Notes)-(CharIndex('} on {', i.inv_Notes) + 6))
AS d
FROM cdms.lester.inventory AS i
join CDMS.lester.vendor AS v ON v.vendor_ID = i.vendor_ID WHERE v.vendor_Name = 'JVE-285') AS s
WHERE PARSENAME(REPLACE(s.d, '/', '.'), 1)+
RIGHT('00'+PARSENAME(REPLACE(s.d, '/', '.'), 3),2)+
RIGHT('00'+PARSENAME(REPLACE(s.d, '/', '.'),2),2) BETWEEN '20110407' AND '20110409'
I tried to cast that to int and do an integer comparison but then I get an error. Figured out that the problem was that some of the inv_Notes fields contain data like "Item Added {3/11/2011}" None of those meet the conditions for the inner select, so in my mind if it's not selected in the inner select, it shouldn't be a problem for the condition of the outer select. However, it was trying to cast 2011{311 to int and throwing an error. I'm sure it was trying to cast that to date and that's why I had the previous problems.
Try adding something similar to this WHERE clause into your statement:
WHERE CAST(SUBSTRING(Notes, CHARINDEX(Notes, 'on {') + 4, Length?) AS Date) BETWEEN StartDate And EndDate
The idea been that you extract the relevant part of the string by combining the SubString and CharIndex methods, and then convert this expression to a date format so that it can be used with the Between Operator.
Best of Luck
Part 2 Update:
As you have been able to select the date but not use it in the where clause, I suggest using it as a select statement and then wrapping this in another statement e.g:
SELECT *
FROM
(SELECT CAST(SUBSTRING(Notes, CHARINDEX(Notes, 'on {') + 4, Length?) AS Date) AS dtmNotes)
WHERE dtmNotes BETWEEN Start And End
This is just to illustrate, but include the whole of your first select statement in the wrapping.
Try this...
assuming that the table with the embedded date is called InventoryList and the column is called inv_Notes
SELECT *
FROM InventoryList i
WHERE
CAST(
substring(
i.inv_Notes,
patindex('%on {%',i.inv_Notes) +4,
patindex('%[0-9][0-9][0-9][0-9]}%',i.inv_Notes)-patindex('%on {%',i.inv_Notes)
) as Datetime)
BETWEEN '12/1/2011' AND '12/23/2011
EDIT: More restrictive looking for a "9/9999}" pattern
SELECT *
FROM InventoryList i
WHERE
CAST(
substring(
i.inv_Notes,
patindex('%on {%',i.inv_Notes) +4,
patindex('%[0-9]/[0-9][0-9][0-9][0-9]}%',i.inv_Notes)-patindex('%on {%',i.inv_Notes)
) as Datetime)
BETWEEN '12/1/2011' AND '12/23/2011

Finding data closest to date?

I have a table
CREATE TABLE `symbol_details` (
`symbol_header_id` int(11) DEFAULT NULL,
`DATE` datetime DEFAULT NULL,
`ADJ_NAV` double DEFAULT NULL
)
with ~20,000,000 entries. Now I want to find the ADJ_NAV value closest to the end of the quarter for just one symbol_header_id:
SET #quarterend = '2009-3-31';
SELECT symbol_header_id AS she, ADJ_NAV AS aend FROM symbol_details
WHERE
symbol_header_id = 18546
AND DATE= (
# date closest after quarter end
SELECT DATE FROM symbol_details
WHERE ABS(DATEDIFF(DATE, #quarterend)) < 10
AND DATE<=#quarterend
AND symbol_header_id = 18546
ORDER BY ABS(DATEDIFF(DATE, #quarterend)) ASC LIMIT 1)
When I run the inner "select date" query it returns quickly. Just running the outer query with the correct date filled in instead of the subquery also finishes very quick. But when I run the whole thing it takes forever - something is wrong?
Seems that the optimizer has some problems to properly evaluate the statement and find the most efficient plan. (In Oracle, I'd ask you to update the statistics, but I'm not sure how the optimizer works in MySQL.)
I'd try some other ways of expressing your statement to see what makes most sense to the optimizer:
explicitly connect the two symbol_header_ids of the immer and the outer query
try a SELECT max(date) .. instead of the 'Order By Limit 1'
try to do a self join of symbol_details
Hope there is a useful idea in here.
You can probably do without the subquery. Just grab the first row:
SELECT *
FROM symbol_details
WHERE DATE <= #quarterend
AND symbol_header_id = 18546
ORDER BY DATE DESC
LIMIT 1
Try:
SELECT t.symbol_header_id,
COALESCE(t.adj_nav, '0.0') 'adj_nav'
FROM SYMBOL_DETAILS t
LEFT JOIN (SELECT sh.symbol_header_id,
MAX(sh.date) 'max_date'
FROM SYMBOL_DETAILS sh
WHERE ABS(DATEDIFF(sh.date, #quarter_end)) < 10
AND sh.date <= #quarter_end) x ON x.symbol_header_id = t.symbol_header_id
AND x.max_date = t.date
WHERE t.symbol_header_id = 18546