LINQ to SQL selecting records and converting dates - sql

I'm trying to select records from a table based on a date using Linq to SQL. Unfortunately the date is split across two tables - the Hours table has the day and the related JobTime table has the month and year in two columns.
I have the following query:
Dim qry = From h As Hour In ctx.Hours Where Convert.ToDateTime(h.day & "/" & h.JobTime.month & "/" & h.JobTime.year & " 00:00:00") > Convert.ToDateTime("01/01/2012 00:00:00")
This gives me the error "Arithmetic overflow error converting expression to data type datetime."
Looking at the SQL query in SQL server profiler, I see:
exec sp_executesql N'SELECT [t0].[JobTimeID], [t0].[day], [t0].[hours]
FROM [dbo].[tbl_pm_hours] AS [t0]
INNER JOIN [dbo].[tbl_pm_jobtimes] AS [t1] ON [t1].[JobTimeID] = [t0].[JobTimeID]
WHERE (CONVERT(DateTime,(((((CONVERT(NVarChar,[t0].[day])) + #p0) + (CONVERT(NVarChar,COALESCE([t1].[month],NULL)))) + #p1) + (CONVERT(NVarChar,COALESCE([t1].[year],NULL)))) + #p2)) > #p3',N'#p0 nvarchar(4000),#p1 nvarchar(4000),#p2 nvarchar(4000),#p3 datetime',#p0=N'/',#p1=N'/',#p2=N' 00:00:00',#p3='2012-01-31 00:00:00'
I can see that it's not passing in the date to search for correctly but I'm not sure how to correct it.
Can anyone please help?
Thanks,
Emma

The direct cause of the error may have to do with this issue.
As said there, the conversions you use are a very inefficient way to build a query. On top of that, it is inefficient because the expressions are not sargable. I.e. you are using a computed value from database columns in a comparison which disables the query analyzer to use indexes to jump to individual column values. So, you could try to fix the error by doctoring the direct cause, but I think it's better to rewrite the query in a way that only the single column values are used in comparions.
I've worked this out in C#:
var cfg = new DateTime(12,6,12);
int year = 12, month = 6, day = 13; // Try some more values here.
// Date from components > datetime value?
bool gt = (
year > cfg.Year || (
(year == cfg.Year && month > cfg.Month) || (
year == cfg.Year && month == cfg.Month && day > cfg.Day)
)
);
You see that it's not as straightforward as it may look at first, but it works. There are much more comparisons to work out, but I'm sure that the ability to use indexes will easily outweigh this.
A more straightforward, but not sargable, way is to use sortable dates, like 20120101 and compare those (as integers).

Related

issue formatting into human time

SELECT
prefix_grade_items.itemname AS Course,
prefix_grade_items.grademax,
ROUND(prefix_grade_grades_history.finalgrade, 0)
AS finalgrade,
prefix_user.firstname,
prefix_user.lastname,
prefix_user.username,
prefix_grade_grades_history.timemodified
FROM
prefix_grade_grades_history
INNER JOIN prefix_user ON prefix_grade_grades_history.userid = prefix_user.id
INNER JOIN prefix_grade_items ON prefix_grade_grades_history.itemid =
prefix_grade_items.id
WHERE (prefix_grade_items.itemname IS NOT NULL)
AND (prefix_grade_items.itemtype = 'mod' OR prefix_grade_items.itemtype = 'manual')
AND (prefix_grade_items.itemmodule = 'quiz' OR prefix_grade_items.itemmodule IS NULL)
AND (prefix_grade_grades_history.timemodified IS NOT NULL)
AND (prefix_grade_grades_history.finalgrade > 0)
AND (prefix_user.deleted = 0)
ORDER BY course
Currently I am trying to polish this query. The problem I am having is using a UNIX Command to convert the time queried from timemodified into Human time. It comes out in epoch time. I have been attempting to use commands such as FROM_UNIXTIME(timestamp,'%a - %D %M %y %H:%i:%s') as timestamp. For reference this is a adhoc query to a moodle server contained in MariaDB. My desired result from the query is that nothing would change as far as the results we are getting, except that the time would be in a month/day/year format instead of the current format.
I have converted the timestamp into a custom date format using the below command in my select query.
DATE_FORMAT(FROM_UNIXTIME(`timestamp`), "%b-%d-%y")
As included in your question where you mention FROM_UNIXTIME(timestamp,'%a - %D %M %y %H:%i:%s'), it is indeed possible to include a second argument in order to specify the specific time/date format you wish to output converted from the UNIX timestamp.
That's the bit that looks like: '%a - %D %M %y %H:%i:%s' - this particular format string will give you an output that looks something like this: Fri - 24th January 20 14:17:09, which as you stated isn't quite what you were looking for, but we can fix that!
For example, the statement below will return the human-readable date (according to the value returned in the timestamp) in the form of month/day/year as you specified as the goal in your question, and would look similar to this: Jan/01/20
FROM_UNIXTIME(timestamp), '%b/%d/%y')
If you instead wish to use a 4 digit year you can substitute the lowercase %y for a capital %Y.
Additionally if a numeric month is instead preferred you can use %m in place of %b.
For a more comprehensive reference on the available specifiers that can be used to build up the format string, this page has a handy table
So putting it all together in the specific context of your original SQL query, using FROM_UNIXTIME to gain the human readable date (along with a suitable format string to specify the format of the output) may look something like this perhaps:
SELECT
prefix_grade_items.itemname AS Course,
prefix_grade_items.grademax,
ROUND(prefix_grade_grades_history.finalgrade, 0) AS finalgrade,
prefix_user.firstname,
prefix_user.lastname,
prefix_user.username,
FROM_UNIXTIME(prefix_grade_grades_history.timemodified, '%b/%d/%Y') AS grademodified
FROM
prefix_grade_grades_history
INNER JOIN prefix_user ON prefix_grade_grades_history.userid = prefix_user.id
INNER JOIN prefix_grade_items ON prefix_grade_grades_history.itemid = prefix_grade_items.id
WHERE (prefix_grade_items.itemname IS NOT NULL)
AND (prefix_grade_items.itemtype = 'mod' OR prefix_grade_items.itemtype = 'manual')
AND (prefix_grade_items.itemmodule = 'quiz' OR prefix_grade_items.itemmodule IS NULL)
AND (prefix_grade_grades_history.timemodified IS NOT NULL)
AND (prefix_grade_grades_history.finalgrade > 0)
AND (prefix_user.deleted = 0)
ORDER BY course
NOTE: I ended up specifying an alias for the timemodified column, calling it instead grademodified. This was done as without an alias the column name ends up getting a little busy :)
Hope that is helpful to you! :)

How can this SQL query be improved?

This code actually works, but I guess it can be done in an easier way, or even more efficient (because I guess comparing strings like that is not a problem but may be). I tried to convert everything into datetime and not string but failed.
This code takes the date and time row from one table, CONCATing them and compares it to the datetime row from another table. The result is: 2019-12-02 09:00:00
It is just a regular Date, Time and Datetime parameters in the table. Like this Date 2019-11-17, Time 09:00:00, Datetime 2019-01-15 16:00:00
SELECT
MAX(CONCAT(f_ini, CONCAT( " ", h_ini)))
FROM posible_work
WHERE
fk_id_asigned = 100573 AND
(SELECT MAX(CONCAT(f_ini, CONCAT( " ", h_ini)))
FROM posible_work) >
(SELECT MAX(RIGHT(f_fin,19)) AS FechaAVI FROM next_work WHERE fk_id_worker = 100573)
Apart from the fact that you force concat() to be called twice when you can use it with 3 arguments (or more), one additional problem would be this condition:
(SELECT MAX(CONCAT(f_ini, CONCAT( " ", h_ini)))
FROM posible_work) >
(SELECT MAX(RIGHT(f_fin,19)) AS FechaAVI FROM next_work WHERE fk_id_worker = 100573)
Why not use in the left side of the inequality just concat(...) and you repeat SELECT...MAX(..)...?
I don't think that this breaks your code's logic:
SELECT
MAX(CONCAT(f_ini, ' ', h_ini))
FROM posible_work
WHERE
fk_id_asigned = 100573
AND
CONCAT(f_ini, ' ', h_ini) >
(SELECT MAX(RIGHT(f_fin,19)) AS FechaAVI FROM next_work WHERE fk_id_worker = 100573)
Also it could be better if you did not hardcode 100573 twice.
Just use aliases properly:
SELECT
MAX(CONCAT(p.f_ini, ' ', p.h_ini))
FROM posible_work p
WHERE
p.fk_id_asigned = 100573
AND
CONCAT(p.f_ini, ' ', p.h_ini) >
(SELECT MAX(RIGHT(f_fin,19)) AS FechaAVI FROM next_work WHERE fk_id_worker = p.fk_id_asigned)

Oracle Query is timing out

I'm trying to write an Oracle query to join data from 4 different tables. The code is below:
SELECT
PROJ.PRJ_NO, PROJ.PRJ_NAME, PROJ.PRJ_BEG_DATE, PROJ.PRJ_END_DATE, PORT.TIER1_NAME, PORT.TIER2_NAME, PORT.TIER3_NAME, MAX(A.FIS_WK_END_DATE) AS "FISCAL_WEEK", SUM(A.ABDOL) AS "AAB_DOL", SUM(A.VHDOL) AS "AVH_DOL", SUM(A.ADOL) AS "AA_DOL", SUM(A.DCDOL) AS "ADC_DOL", SUM(A.DCGADOL) AS "ADC_GA_DOL", SUM(A.COM) AS "AM_DOL", SUM(A.FE) AS "AFE_DOL", SUM(A.IE) AS "AIE_DOL", SUM(A.OTHER) AS "AR_DOL", SUM(A.MTSFT) AS "AS_FT", SUM(A.MTSST) AS "AS_ST", SUM(A.ACTST) AS "AL_ST", SUM(A.ACTFT) AS "ALL_FT", MAX(P.SNAPSHOT_DATE) as "SNAP_DATE", P.FINSCN_TYPE, SUM(P.ABDOL) AS "PAB_DOL", SUM(P.VHDOL) AS "PVH_DOL", SUM(P.DCDOL) AS "PDC_DOL", SUM(P.TCI_DOL) AS "PCI_GA_DOL", SUM(P.GADOL) AS "PN_GA_DOL", SUM(P.COM) AS "PN_COM", SUM(P.FEE) AS "PN_FEE", SUM(P.D_IE) AS "PN_MOIE", SUM(P.OTHER) AS "PN_OTHER"
FROM PROJ_TASK_VW PROJ
LEFT JOIN PORTFOLIO_VW PORT
ON PROJ.TASKNO = PORT.TASKNO
LEFT JOIN ACTUAL_VW A
ON PROJ.TASKNO = A.CURR_TASKNO
LEFT JOIN BUDG_DOLL_VW P
ON PROJ.TASKNO = P.CURR_TASKNO
WHERE TO_CHAR(PROJ.PRJ_END_DATE, 'YYYY-MM-DD') > '2018-10-01'
AND PROJ.P_FLAG = 'N'
AND (PROJ.P_TYPE LIKE 'D-%' OR PROJ.P_TYPE LIKE '%MR%' OR PROJ.P_TYPE LIKE '%ID%')
AND (SUBSTR(PROJ.PRJ_NO,3,3) != 'BP' AND SUBSTR(PROJ.PRJ_NO,3,3) != 'PJ')
AND (P.FINSCN_TYPE = 'SR' OR P.FINSCN_TYPE = 'BUG')
AND (A.ABDOL + A.VHDOL + A.ADOL + A.DCDOL + A.DCGADOL + A.COM +
A.FE + A.IE + A.OTHER) <> 0
GROUP BY
PROJ.PRJ_NO,
PROJ.PRJ_NAME,
PROJ.PRJ_BEG_DATE,
PROJ.PRJ_END_DATE,
PORT.TIER1_NAME,
PORT.TIER2_NAME,
PORT.TIER3_NAME,
P.FINSCN_TYPE
My overall intent is to bring all of the select fields into a single table using left joins (using table "PROJ" as the parent table and the remaining tables providing child data based on the data returned from the "PROJ" table. When the query is ran it times out after about 30mins. Is there a better way to write this query to where I can build the table I need without timing out???
First, there's no way to answer this question without an execution plan. What columns do you have indexed? But here are some things I noticed.
WHERE TO_CHAR(PROJ.PRJ_END_DATE, 'YYYY-MM-DD') > '2018-10-01'
Your column is a date, so you should be comparing to a date, rather than converting to a VARCHAR2 and doing an inequality on strings.
AND (PROJ.P_TYPE LIKE 'D-%' OR PROJ.P_TYPE LIKE '%MR%' OR PROJ.P_TYPE LIKE '%ID%')
I'm not sure, but these will likely not be very performant because of the wildcards. Indexes might make these better, but I never remember how wildcard searches work with indexes.
AND (SUBSTR(PROJ.PRJ_NO,3,3) != 'BP' AND SUBSTR(PROJ.PRJ_NO,3,3) != 'PJ')
These do nothing since your two SUBSTRs return strings of 3 characters long and you are comparing them to 2 character long strings.
AND (A.ABDOL + A.VHDOL + A.ADOL + A.DCDOL + A.DCGADOL + A.COM + A.FE + A.IE + A.OTHER) <> 0
Do you actually care about the sum here, or are you just checking that one or more of these values is non-zero. If these values are always > 0, then you're better off replacing this with:
AND ( a.ABDOL > 0 OR A.VHDOL > 0 ...

Date comparison on Kayako Query Language - KQL

I am using Kayako Querying Language and trying to get the query to return all closed/resolved, closed/unresolved, and review tickets from a specified month. When I run the query, every ticket ever comes up, and it seems to ignore the date function I am using. What am I doing wrong?
SELECT COUNT(*) AS Total
FROM ‘Tickets'
WHERE ‘Tickets.Creation Date’ = month(June 2016) AND ‘Tickets.Status’ = ‘Closed’ OR ‘Tickets.Status’ = ‘Resolved’ OR ‘Tickets.Status’ = ‘Unresolved'
GROUP BY ‘Tickets.Status'
Thanks.
Replace the date comparison in your WHERE clause for this:
WHERE 'Tickets.Creation Date':Month = 6 and 'Tickets.Creation Date':Year = 2016
Be also careful with the quotes, you sometimes use ‘ and others '

Comparing Date Values in Access - Data Type Mismatch in Criteria Expression

i'm having an issue comparing a date in an access database. basically i'm parsing out a date from a text field, then trying to compare that date to another to only pull newer/older records.
so far i have everything working, but when i try to add the expression to the where clause, it's acting like it's not a date value.
here's the full SQL:
SELECT
Switch(Isdate(TRIM(LEFT(bc_testingtickets.notes, Instr(bc_testingtickets.notes, ' ')))) = false, 'NOT ASSIGNED!!!') AS [Assigned Status],
TRIM(LEFT(bc_testingtickets.notes, Instr(bc_testingtickets.notes, ' '))) AS [Last Updated Date],
bc_testingtickets.notes AS [Work Diary],
bc_testingtickets.ticket_id,
clients.client_code,
bc_profilemain.SYSTEM,
list_picklists.TEXT,
list_picklists_1.TEXT,
list_picklists_2.TEXT,
list_picklists_3.TEXT,
bc_testingtickets.createdate,
bc_testingtickets.completedate,
Datevalue(TRIM(LEFT([bc_TestingTickets].[notes], Instr([bc_TestingTickets].[notes], ' ')))) AS datetest
FROM list_picklists AS list_picklists_3
RIGHT JOIN (list_picklists AS list_picklists_2
RIGHT JOIN (list_picklists AS list_picklists_1
RIGHT JOIN (bc_profilemain
RIGHT JOIN (((bc_testingtickets
LEFT JOIN clients
ON
bc_testingtickets.broker = clients.client_id)
LEFT JOIN list_picklists
ON
bc_testingtickets.status = list_picklists.id)
LEFT JOIN bc_profile2ticketmapping
ON bc_testingtickets.ticket_id =
bc_profile2ticketmapping.ticket_id)
ON bc_profilemain.id =
bc_profile2ticketmapping.profile_id)
ON list_picklists_1.id = bc_testingtickets.purpose)
ON list_picklists_2.id = bc_profilemain.destination)
ON list_picklists_3.id = bc_profilemain.security_type
WHERE ( ( ( list_picklists.TEXT ) <> 'Passed'
AND ( list_picklists.TEXT ) <> 'Failed'
AND ( list_picklists.TEXT ) <> 'Rejected' )
AND ( ( bc_testingtickets.ticket_id ) <> 4386 ) )
GROUP BY bc_testingtickets.notes,
bc_testingtickets.ticket_id,
clients.client_code,
bc_profilemain.SYSTEM,
list_picklists.TEXT,
list_picklists_1.TEXT,
list_picklists_2.TEXT,
list_picklists_3.TEXT,
bc_testingtickets.createdate,
bc_testingtickets.completedate,
DateValue(TRIM(LEFT([bc_TestingTickets].[notes], Instr([bc_TestingTickets].[notes], ' '))))
ORDER BY Datevalue(TRIM(LEFT([bc_TestingTickets].[notes], Instr([bc_TestingTickets].[notes], ' '))));
the value i'm trying to compare against a various date is this:
DateValue(Trim(Left([bc_TestingTickets].[notes],InStr([bc_TestingTickets].[notes],' '))))
if i add a section to the where clause like below, i get the Data Type Mismatch error:
WHERE DateValue(Trim(Left([bc_TestingTickets].[notes],InStr([bc_TestingTickets].[notes],' ')))) > #4/1/2012#
i've even tried using the DateValue function around the manual date i'm testing with but i still get the mismatch error:
WHERE DateValue(Trim(Left([bc_TestingTickets].[notes],InStr([bc_TestingTickets].[notes],' ')))) > DateValue("4/1/2012")
any tips on how i can compare a date in this method? i can't change any fields in the database, ect, that's why i'm parsing the date in SQL and trying to manipulate it so i can run reports against it.
i've tried googling but nothing specifically talks about parsing a date from text and converting it to a date object. i think it may be a bug or the way the date is being returned from the left/trim functions. you can see i've added a column to the end of the SELECT statement called DateTest and it's obvious access is treating it like a date (when the query is run, it asks to sort by oldest to newest/newest to oldest instead of A-Z or Z-A), unlike the second column in the select.
thanks in advance for any tips/clues on how i can query based on the date.
edit:
i just tried the following statements in my where clause and still getting a mismatch:
CDate(Trim(Left([bc_TestingTickets].[notes],InStr([bc_TestingTickets].[notes],' ')))) > #4/1/2012#
CDate(Trim(Left([bc_TestingTickets].[notes],InStr([bc_TestingTickets].[notes],' ')))) >
CDate("4/1/2012") CDate(DateValue(Trim(Left([bc_TestingTickets].[notes],InStr([bc_TestingTickets].[‌​notes],' '))))) > #4/1/2012#
i tried with all the various combinations i could think of regarding putting CDate inside of DateValue, outside, ect. the CDate function does look like what i should be using though. not sure why it's still throwing the error.
here's a link to a screenshot showing the results of the query http://ramonecung.com/access.jpg. there's two screenshots in one image.
You reported you get Data Type Mismatch error with this WHERE clause.
WHERE DateValue(Trim(Left([bc_TestingTickets].[notes],
InStr([bc_TestingTickets].[notes],' ')))) > #4/1/2012#
That makes me wonder whether [bc_TestingTickets].[notes] can ever be Null, either because the table design allows Null for that field, or Nulls are prohibited by the design but are present in the query's set of candidate rows as the result of a LEFT or RIGHT JOIN.
If Nulls are present, your situation may be similar to this simple query which also triggers the data type mismatch error:
SELECT DateValue(Trim(Left(Null,InStr(Null,' '))));
If that proves to be the cause of your problem, you will have to design around it somehow. I can't offer a suggestion about how you should do that. Trying to analyze your query scared me away. :-(
It seems like you are having a problem with the type conversion. In this case, I believe that you are looking for the CDate function.
A problem might be the order of the date parts. A test in the Immediate window shows this
?cdate(#4/1/2012#)
01.04.2012
?cdate(#2012/1/4#)
04.01.2012
Write the dates backwards in the format yyyy/MM/dd and thus avoiding inadverted swapping of days and months!
DateValue("2012/1/4")
and
CDate(#2012/1/4#)