I have developed a large piece of coding, to get order information from our database. This has previously been working fine, capturing 1000s of lines of data in less than a second.
However, recently the specification has changed. We have moved from being Monday to Monday to the intention of running our orders from Saturday through Friday.
This has meant rewriting the code including case statements the following is an example:
*(Previous)*
,Case When To_Char(obd.due_date, 'YYYYIW') = To_Char(sysdate, 'YYYYIW') Then 'Current Week'
*(Now)*
,Case When TO_DATE(obd.due_date, 'DD-MM-YYYY') BETWEEN (TO_DATE(TO_CHAR(TRUNC(TO_DATE(SYSDATE,'DD-MM-YYYY'), 'WW')-2,'DD-MON-YYYY'))) AND (TO_DATE(TO_CHAR(TRUNC(TO_DATE(SYSDATE,'DD-MM-YYYY'), 'WW')+5,'DD-MON-YYYY'))) Then 'Current Week'
However I now lose the index on the fields due to conversion and thus the time for the data to be accessed has increased dramatically.
Any help would be greatly appreciated.
I doubt that your "previous" calculation used an index (and it's used in a CASE, not a WHERE).
You should always try to get a searchable argument, i.e. calculation only on one side of the comparison:
WHEN obd.due_date >= next_day(trunc(current_date) , 'sat')-7
AND obd.due_date < next_day(trunc(current_date) , 'sat')
should be what you want
Related
Scenario
A user selects a date. Based on the selection I check whether the date & time is booked or not (No issues here).
If a date & time is booked, I need to show them n alternative dates. Based on their date and time parameters, and those proposed alternative dates have to be as close as to their chosen date as possible. The list of alternative dates should start from the date the query is ran on My backend handles this.
My Progress So Far
SELECT alternative_date
FROM GENERATE_SERIES(
TIMESTAMP '2022-08-20 05:00:00',
date_trunc('month', TIMESTAMP '2022-08-20 07:00:00') + INTERVAL '1 month - 1 day',
INTERVAL '1 day'
) AS G(alternative_date)
WHERE NOT EXISTS(
SELECT * FROM events T
WHERE T.bookDate::DATE = G.alternative_date::DATE
)
The code above uses the GENERATE_SERIES(...) function in PSQL. It searches for all dates, starting from 2022-08-20, and up to the end of August. It specifically returns the dates which does not exist in the bookDate column (Meaning it has not yet been booked).
Problems I Need Help With
When searching for alternative dates, I'm providing 3 important things
The user's preferred booking date, so I can suggest which other dates are close to him that he can choose? How would I go about doing this? It's the part where I'm facing most trouble.
The user's start and end times, so when providing a list of alternative dates, I can tell him, hey there's free space between 06 and 07 on the date 2022-08-22 for instance. I'm also facing some issues here, a push in the right track will be great!
I want to add another WHERE but it fails, the current WHERE is a NOT EXISTS so it looks for all dates not equaling to what is given. My other WHERE basically means WHERE the place is open for booking or not.
To get closest free dates, you can ORDER BY your result by "distance" of particular alternative date to user's preferred date - the shortest intervals will be first:
ORDER BY alternative_date - TIMESTAMP '2022-08-20 05:00:00'
If you want to recommend time slots smaller than whole dates (hour range), you need to switch the whole thing from dates to hours, i.e. generate_series from 1 day to 1 hour (or whatever your smallest bookable unit is) and excluse invalid hours (nighttime I assume) in WHERE. From there, it is pretty much the same as with dates.
As for "second where", there can be only one WHERE, but it can be composed from multiple conditions - you can add more conditions using AND operator (and it can also be sub-query if needed):
WHERE NOT EXISTS(
SELECT * FROM events T
WHERE T.bookDate::DATE = G.alternative_date::DATE
) AND NOT EXISTS (
SELECT 1 FROM events WHERE "roomId" = '13b46460-162d-4d32-94c0-e27dd9246c79'
)
(warning: this second sub-query is probably dangerous in real world, since the room will be used more than one time, I assume, so you need to add some time condition to the subquery to check against date)
I have an issue with a formula case statement in a NetSuite workflow, I am using the same case statement in a saved search and it works just fine, but generates an error in the workflow formula for sourcing date, to set the date field on a cashsale record created from a sales order.
NetSuite formula which basically states if it is 10:00 PM (22:00) or after increment by one day, otherwise use datecreated date. (this is used to calculate settlement date for banking reconciliation matching)
The workflow event is "Before Record Load" on "Create" a Cashsale record which is definitely a server-side event. I have also independently pulled out
to_date({createdfrom.datecreated}) + 1
and
{createdfrom.datecreated}
Which work independently as expected without errors, really not sure what I am doing wrong
CASE WHEN to_number(to_char({createdfrom.datecreated}, 'HH24')) >= 22 THEN to_date({createdfrom.datecreated}) + 1 ELSE {createdfrom.datecreated} END
Here is the case statement I used in my saved search which works perfectly
CASE WHEN to_number(to_char({datecreated}, 'HH24')) >= 22 THEN to_char(({datecreated} + 1), 'DD/MM/YYYY') ELSE to_char(({datecreated}), 'DD/MM/YYYY') END
so basically in a before load create record user event use:
CASE WHEN to_number(to_char({sysdate}, 'HH24')) >= 22 THEN {sysdate} + 1 ELSE {sysdate} END
I see you have clarified your question.
{trandate} is a date field while the formula is producing a datetime field
So since your formula is meant to populate a date field you have to convert the datetime to a date:
TRUNC(CASE WHEN to_number(to_char({createdfrom.datecreated}, 'HH24')) >= 22 THEN {createdfrom.datecreated} + 1 ELSE {createdfrom.datecreated} END)
Unfortunately Netsuite Workflow formula value is not reliable in terms of using the Netsuite formulas that run in saved search. Some work and some don’t. In this case the To_char and date formatting seems to be not recognized at all.
Solution is a custom field named “Created Hours” that is dynamically sourcing value from a saved search. The field is exposed in Sales Order and Cash Sale transaction form (You can hide it as well). I then use the field as my comparison to achieve the condition that will set the date value. I tested few old Sales orders converting to Cash Sales and works well
Custom field hours
Hours saved search
Workflow to evaluate hours
Hope this helps other people with the same or similar issues.
I have a list of items I'd like to view by the date they most recently occurred. I am currently using this query.
SELECT Cleaning1, Max(Date1) AS most_recent
FROM CleaningLog
GROUP BY Cleaning1;
It worked yesterday when I was at work, but suddenly stopped working. It won't show to most recent date an event occurred for some of the items. I was wondering why this would suddenly stop working. I added date parameters to the four queries I have with this code. When that stopped working correctly, I decided to create a test query, without date parameters, and it still won't show me the most recent event that I typed in.
I tried playing around with the <, >, = signs in the date portion of the code, but nothing seems to capture the dates I added this morning. I should mention this is what I have for codes that have a date parameter:
SELECT Cleaning1, Max(Date1) AS most_recent
FROM CleaningLog
GROUP BY Cleaning1
HAVING Max(Date1) < Now() - 30;
What do you think would be a potential cause for this query to stop capturing dates? The dates in my database are not in chronological order, because I had to manually type in events that occurred in the past. Any help would be appreciated!
It seems like it won't use the data after ID 89. It worked fine yesterday afternoon. I added from ID 59 on this morning. All of the data was added the same way, through a form:
Convert your text date to a true date:
SELECT
Cleaning1,
Max(CDate(Date1)) AS most_recent
FROM
CleaningLog
GROUP BY
Cleaning1
HAVING
Max(CDate(Date1)) < Date() - 30;
Whenever you write a query where you need to filter out rows on a range of values - then should I use the BETWEEN clause or <= and >= ?
Which one is better in performance?
Neither. They create exactly the same execution plan.
The times where I use them depends not on performance, but on the data.
If the data are Discrete Values, then I use BETWEEN...
x BETWEEN 0 AND 9
But if the data are Continuous Values, then that doesn't work so well...
x BETWEEN 0.000 AND 9.999999999999999999
Instead, I use >= AND <...
x >= 0 AND x < 10
Interestingly, however, the >= AND < technique actually works for both Continuous and Discrete data types. So, in general, I rarely use BETWEEN at all.
Also, don't use BETWEEN for date/time range queries.
What does the following really mean?
BETWEEN '20120201' AND '20120229'
Some people think that means get me the all the data from February, including all of the data anytime on February 29th. The above gets translated to:
BETWEEN '20120201 00:00:00.000' AND '20120229 00:00:00.000'
So if there is data on the 29th any time after midnight, your report is going to be incomplete.
People also try to be clever and pick the "end" of the day:
BETWEEN '00:00:00.000' AND '23:59:59.997'
That works if the data type is datetime. If it is smalldatetime the end of the range gets rounded up, and you may include data from the next day that you didn't mean to. If it's datetime2 you might actually miss a small portion of data that happened in the last 2+ milliseconds of the day. In most cases statistically irrelevant, but if the query is wrong, the query is wrong.
So for date range queries I always strongly recommend using an open-ended range, e.g. to report on the month of February the WHERE clause would say "on or after February 1st, and before March 1st" as follows:
WHERE date_col >= '20120201' AND date_col < '20120301'
BETWEEN can work as expected using the date type only, but I still prefer an open-ended range in queries because later someone may change that underlying data type to allow it to include time.
I blogged a lot more details here:
What do BETWEEN and the devil have in common?
I know there are lots of these types of questions, but i didn't see one that was similar enough to my criteria. So i'd like to ask for your help please. The fields i have are just start and end which are of time types. I cannot involve any specific dates in this. If the time ranges don't go pass midnight across day, i'd just compare two tuples as such:
end1 > start2 AND start1 < end2
(end points touching are not considered overlapped here.)
But when I involve time range that pass (or at) midnight, this obviously doesn't work. For example, given:
start | end
--------+--------
06:00PM | 01:00AM
03:00PM | 09:00PM
Without involving dates, how can i achieve this, please. My assumption is, if end is less than start, then we're involving 2 days.
I'm trying to do this in plain standard SQL, so just a simple and concise logic in the WHERE clause.
Thank you everyone!
Added:
Also, how would I test if one time range completely envelopes another? thanks again!
If your SQL supports time differences:
(end1 - start1) > (start2 - start1) AND (end2 - start2) > (start1 - start2)
Unfortunately, "plain" SQL will be too general to use against an actual database. The reason is that the various database products have different levels of support for calculating the duration between two times. For example, in SQL Server 2008, it would be substantially simpler to convert the time values to DateTime and then do the comparison since many comparison operators are not supported on the Time data type.
Select ...
From (
Select Cast(T.Start1 As DateTime) As Start1
, Case
When Cast(T.Start1 As DateTime) > Cast(T.End1 As DateTime) Then DateAdd(d,1,Cast(T.End1 As DateTime))
Else Cast(T.End1 As DateTime)
End As End1
From ...
) As T
Where T.End1 > T2.Start2 And T1.Start2 < T2.End2
use start time and duration (in minutes or whatever unit is appropriate)
The program Transtar had this problem. The time data was not associated with any date, nor was the time data in a date time field. The program initially was designed to issue transit itinaries from about 4AM to midnight which worked fine as long as the transit wasn't around the clock. I built a function which did a sliding test for the times so that if you asked for 5AM it would look at times from 1AM to 12:59AM. I wrote it in FORTRAN, but the algorythm would be the same regardless of language.