How to use the current date format in a SQL Query - sql

I am trying to do a query that calculates the days of past due library books in days. I also want to display the Patron's Last Name ( the person who borrowed the book), Book Title, the Due Date of the book.
I ran a simple query to understand what I am looking for. The code I ran is as follows:
SELECT PATRON.PAT_LNAME, BOOK.BOOK_TITLE, CHECKOUT.CHECK_DUE_DATE,
CHECKOUT.CHECK_IN_DATE
FROM CHECKOUT, BOOK, PATRON
WHERE CHECKOUT.BOOK_NUM=BOOK.BOOK_NUM
AND CHECKOUT.PAT_ID= PATRON.PAT_ID
AND CHECK_IN_DATE IS NULL
I need to calculate the days that the book is overdue from the date that it was due. I want to use the current date to calculate the days that the book is overdue, although I am not sure how to do that. I know there is a SYSDATE function that gives the current date. I do not know how to use the SYSDATE function.

I think the marker for a past due book is that the current date is greater than the due date. So you can just compare the due date against SYSDATE to determine which books are overdue and by how many days.
SELECT
p.PAT_LNAME,
b.BOOK_TITLE,
c.CHECK_DUE_DATE,
c.CHECK_IN_DATE,
SYSDATE - c.CHECK_DUE_DATE AS num_days_due
FROM CHECKOUT c
INNER JOIN BOOK b
ON c.BOOK_NUM = b.BOOK_NUM
INNER JOIN PATRON p
ON c.PAT_ID = p.PAT_ID
WHERE
c.CHECK_IN_DATE IS NULL AND
SYSDATE > c.CHECK_DUE_DATE;
In Oracle we can just subtract two dates to get the difference in days. Note also that I replaced your implicit inner joins with explicit joins. This is the preferred way of writing a join query.

Related

SQL query to count number of checkins per month

To put a long story short, I am working on a database using PostgreSQL that is managing yelp checkins. The checkintable has the attributes business_id(string), date(string in form yyyy-mm-dd), and time(string in form 00:00:00).
What I simply need to do is, given a business_id, I need to return a list of the total number of checkins based on just the mm (month) value.
So for instance, I need to retrieve the total checkins that were in Jan, Feb, March, April, etc, not based upon the year.
Any help is greatly appreciated. I've already considered group by clauses but I didn't know how to factor in '%mm%'.
Reiterating Gordon, class or not, storing dates and times as strings makes things harder, slower, and more likely to break. It's harder to take advantage of Postgres's powerful date math functions. Storing dates and times separately makes things even harder; you have to concatenate them together to get the full timestamp which means it will not be indexed. Determining the time between two events becomes unnecessarily difficult.
It should be a single timestamp column. Hopefully your class will introduce that shortly.
What I simply need to do is, given a business_id, I need to return a list of the total number of checkins based on just the mm (month) value.
This is deceptively straightforward. Cast your strings to dates, fortunately they're in ISO 8601 format so no reformatting is required. Then use extract to extract just the month part.
select
extract('month' from checkin_date::date) as month,
count(*)
from yelp_checkins
where business_id = ?
group by month
order by month
But there's a catch. What if there are no checkins for a business on a given month? We'll get no entry for that month. This is a pretty common problem.
If we want a row for every month, we need to generate a table with our desired months with generate_series, then left join with our checkin table. A left join ensures all the months (the "left" table) will be there even if there is no corresponding month in the join table (the "right" table).
select
months.month,
count(business_id)
from generate_series(1,12) as months(month)
left join yelp_checkins
on months.month = extract('month' from checkin_date::date)
and business_id = ?
group by months.month
order by months.month
Now that we have a table of months, we can group by that. We can't use a where business_id = ? clause or that will filter out empty months after the left join has happened. Instead we must put that as part of the left join.
Try it.
Why would you store the date as a string? That is a broken data model. You should fix the data.
That said, I recommend converting a date and truncating to the first day of the month:
select date_trunc('day', datestr::date) as yyyymm, count(*)
from t
group by yyyymm
order by yyyymm;
If you don't want these based on the year, then use extract():
select extract(month from datestr::date) as mm, count(*)
from t
group by mm
order by mm;

Is there a simple line (or two) of code that will pull records before a minimum date in another table?

I want to pull Emergency room visits before a members first treatment date. Everyone as a different first treatment date and none occur before Jan 01 2012.
So if a member has a first treatment date of Feb 24 2013, I want to know how many times they visited the ER one year prior to that date.
These min dates are located in another table and I can not use the Min date in my DATEADD function. Thoughts?
One possible solution is to use a CTE to capture the visits between the dates your interested in and then join to that with your select.
Here is an example:
Rextester
Edit:
I just completely updated my answer. Sorry for the confusion.
So you have at least two tables:
Emergency room visits
Treatment information
Let's call these two tables [ERVisits] and [Treatments].
I suppose both tables have some id-field for the patient/member. Let's call it [MemberId].
How about this conceptual query:
WITH [FirstTreatments] AS
(
SELECT [MemberId], MIN([TreatmentDate]) AS [FirstTreatmentDate]
FROM [Treatments]
GROUP BY [MemberId]
)
SELECT V.[MemberId], T.[FirstTreatmentDate], COUNT(*) AS [ERVisitCount]
FROM [ERVisits] AS V INNER JOIN [FirstTreatments] AS T ON T.[MemberId] = V.[MemberId]
WHERE DATEDIFF(DAY, V.[VisitDate], T.[FirstTreatmentDate]) BETWEEN 0 AND 365
GROUP BY V.[MemberId], T.[FirstTreatmentDate]
This query should show the number of times a patient/member has visited the ER in the year before his/her first treatment date.
Here is a tester: https://rextester.com/UXIE4263

Criteria in SQL/ms-access is only considering day of the month, not full date

NB: this is a follow up question from Syntax of MS Access/SQL sub-query including aggregate functions.
I am trying to produce a database to manage maintenance of equipment. I have two tables:
One (Inventory) containing details of each piece of equipment, including Purchase Date and Service Period,
One containing details of work done (WorkDone), including the date the work was carried out (Work Date).
I would like a query that displays the date that it should be next serviced. So far I have:
SELECT Max(NZ(DateAdd('m', i.[Service Period], w.[Work Date]),
DateAdd('m', i.[Service Period], i.[Purchase Date]))
) AS NextServiceDate, i.Equipement
FROM Inventory i LEFT JOIN WorkDone w ON i.ID = w.Equipment
GROUP BY i.Equipement
I would now like to order by NextServiceDate and only show entries where NextServiceDate is in the next week. However adding
HAVING (((Max(Nz(DateAdd('m',i.[Service Period],w.[Work Date]),DateAdd('m',i.[Service Period],i.[Purchase Date]))))<DateAdd('ww',1,Date()))
ORDER BY Max(Nz(DateAdd('m',i.[Service Period],w.[Work Date]),DateAdd('m',i.[Service Period],i.[Purchase Date])));
only shows when the day of the month is less than one week from now (e.g. if it is the 1st today it will show all entries where NextServiceDate occurs in the first 7 days of any month of any year, past or future). For some reason it is only considering the day of the month and not the full date. I don't understand why...
NB: I have a British system so date format is dd-mm-yyyy.
After a cursory review of your code, I'm unsure whether the instances of i.Equipement is a typo (since your JOIN clause refers to a similar field w.Equipment), or whether these two fields are intentionally named differently?
I can't see anything else immediately wrong with your code, but it may be clearer and easier to debug if you were to restructure the code to the following:
SELECT
Max(sub.dat) as NextServiceDate, sub.eqp
FROM
(
SELECT
DateAdd('m',i.[Service Period],Nz(w.[Work Date],i[Purchase Date])) as dat, i.Equipement as eqp
FROM
Inventory i LEFT JOIN WorkDone w ON i.ID = w.Equipment
) AS sub
GROUP BY
sub.eqp
HAVING
Max(sub.dat) < DateAdd('ww',1,Date())
ORDER BY
Max(sub.dat)
Note that the difference in regional date formats will only have an effect when you are specifying literal dates (for example, as criteria), in which case you would need to adhere to the format #mm/dd/yyyy#.

SQL Select Items and link field to another table in same select

Currently I am retrieving a list of Purchase Orders Lines (POL) and each has a Due Date. For each line where the POL.Due Date is a future date i.e. >= Current Date, I need to determine the Period Name and Financial Week the POL.Due Date falls into.
The SQL Database has a table for the Financial Period and one for the Financial Week. Each table is driven by a date.
PERIODPER
PERIOD_DATE
PERIOD
PERIOD_NAME
PERIOD_YEAR
PERIOD_WEEK
START_DATE
WEEK
YEAR
Against each report line along with the Due Date I am trying to link to each of the above tables to determine the PERIOD_NAME and WEEK for the POL.Due Date.
Where the POL.Due Date has elapsed i.e. < Current Date, I need to retrieve the PERIOD_NAME and WEEK for the Current Date.
I would like to try and do this in an SQL select as my only other option is to write a VBA report which initially retrieves all the Purchase Order Lines and then serially reads through each and links to the other tables to determine the Financial Period Name and Week Number.
I am looking for an end result something on the lines of:
PO_NUMBER PO_LINE DUE_DATE WEEK_NO PERIOD_NAME
I would appreciate any assistance on this as my SQL knowledge does not extend to what to me appears to be a complex selection.
Do you mean something like this (SQL Server syntax)?
select pol.po_number,
pol.po_line,
pol.due_date,
pw.week as week_no,
pp.period_name
from purchaseOrderLines pol
left join period_week pw on pol.DueDate > GetDate()
and pw.start_date <= pol.due_date
and dateAdd(d, 7, pw.start_date) >= pol.due_date
left join periodPer pp on pol.DueDate > GetDate()
and pp.period_date = pol.DueDate
Thanks for your response.
I tried your logic which gave me what I was looking for but upon further investigation I located another table which detailed every date up to 2025, including the week and month. I'm simply now creating a JOIN to this new table using my Due Date value.
I would just like to thank you for your time and effort in answering my query. Although I am not using your suggestion for the stated example, I am however looking at what you've presented, and it certainly gives me a few ideas for some other SELECT statements I'm currently working on.

Selecting records from the past three months

I have 2 tables from which i need to run a query to display number of views a user had in the last 3 months from now.
So far I have come up with: all the field types are correct.
SELECT dbo_LU_USER.USERNAME
, Count(*) AS No_of_Sessions
FROM dbo_SDB_SESSION
INNER JOIN dbo_LU_USER
ON dbo_SDB_SESSION.FK_USERID = dbo_LU_USER.PK_USERID
WHERE (((DateDiff("m",[dbo_SDB_SESSION].[SESSIONSTART],Now()))=0
Or (DateDiff("m",[dbo_SDB_SESSION].[SESSIONSTART],Now()))=1
Or (DateDiff("m",[dbo_SDB_SESSION].[SESSIONSTART],Now()))=2))
GROUP BY dbo_LU_USER.USERNAME;
Basically, the code above display a list of all records within the past 3 months; however, it starts from the 1st day of the month and ends on the current date, but I need it to start 3 months prior to today's date.
Also to let you know this is SQL View in MS Access 2007 code.
Thanks in advance
Depending on how "strictly" you define your 3 months rule, you could make things a lot easier and probably efficient, by trying this:
SELECT dbo_LU_USER.USERNAME, Count(*) AS No_of_Sessions
FROM dbo_SDB_SESSION
INNER JOIN dbo_LU_USER
ON dbo_SDB_SESSION.FK_USERID = dbo_LU_USER.PK_USERID
WHERE [dbo_SDB_SESSION].[SESSIONSTART] between now() and DateAdd("d",-90,now())
GROUP BY dbo_LU_USER.USERNAME;
(Please understand that my MS SQL is a bit rusty, and can't test this at the moment: the idea is to make the query scan all record whose date is between "TODAY" and "TODAY-90 days").