Left Join of two tables based on a range of dates - sql

I am a newbie to SQL coding and am trying to figure out how to create a LEFT JOIN statement based on a date range. The database is analytics from a smartphone app that sends messages to users. The two tables are messageLog (which describes the messages sent to each user) and messageOpenLog (which describes the messages that are opened). Both tables are linked to the message table, but not to each other. To complicate matters, there are a couple other rules we have developed on when messages are able to be sent:
If a message is not opened within 7 days, the message can be resent on day 8.
If a message is opened, then the message can be resent within 60 days.
So, what I want to do is join the two tables together based on the following pseudocode (as I have no idea where to start with actual code):
LEFT JOIN
If (messageOpenLog.DateOpened is within 7 days of messageLog.DateSent)
and messageLog.message_id = messageOpenLog.message_id and
messageLog.user_id = messageOpenLog.user_id
Note: the date format is yyyy-mm-dd hh:mm:ss in both tables.
Any help you can provide would be greatly appreciated.

I am unable to comment on shn's answer, but there is a chance that the user has never opened the message and a messageOpenLog record has not been created. In that case you could add a messageOpenLog.message_id is null to the where clause and get those unopened messages with no corresponding messageOpenLog record as well.

I would suggest:
messagelog ml LEFT JOIN
messageOpenLog mol
ON mol.message_id = ml.message_id AND
mol.user_id = ml.user_id AND
mol.DateOpened >= ml.DateSent AND -- probably not needed
mol.DateOpened < ml.DateSent + interval '7 day'
Note that date arithmetic varies a lot among databases. The exact syntax for adding seven days may be a bit different in your database.

From what I understand from your question and the query below, you are finding all the individual messages that have a time difference of longer than 7 days between their send date and open date.
To do the time difference I would recommend using the DATEDIFF() function that is built into SQL (you may need to format the timestamps into date format with DATE()).
Since the two tables are not directly related you could do something like this:
SELECT
messageOpenLog.*,
messageLog.*
FROM
messageLog LEFT JOIN messageOpenLog ON messageLog.message_id=messageOpenLog.message_id
WHERE
messageLog.user_id = messageOpenLog.user_id AND
DATEDIFF(
day,
DATE(messageLog.timestamp),
DATE(messageOpenLog.timestamp)
) > 7
The structure of this query is dependent on the construction of your tables.
Notice I used the .timestamp column but in your tables this may be named different.
Also I'm not sure if this is actually what you want; if you want to see if the message is more than 7 days old, a different query is required.
Assuming that there is only one messageSent row, this query will get all of the messageOpen rows for the same message that are more than 7 days old.
It's very difficult to give you an exact query based on the information that was presented, such as the potential number of rows with the same message_id, as #amac mentions, there could also be cases where one of the tables has no rows with a certain message_id.

Related

Time gap calculation in MS Access

I have a table (Access 2016) tbl_b with date/time registrations
b_customer (num)
b_date (date)
b_start (date/time)
b_end (date/time)
I want to make a chart of all time registrations per day in a selected month and the gaps between those times. For this I need a query or table showing all times as source for the chart. I’m a bit lost how to approach this.
I assume the chart source needs consecutive records with all date and time registrations to do this. My approach would be create a temporary table (tmp) calculating all time periods where the customer is null. The next step would be a union query to combine the tbl_b and tmp table.
The tbl_b does not have records for every day, so I use a query generating all days in the selected month which shall be used in the chart (found this solution here: [Create a List of Dates in Access Query)
The disadvantage of using a tmp table for the “time gaps” is that it is not updating real time, where a query would provide this opportunity. I have about 20 queries to perform the end result, but MS Access keeps giving (expected) errors that the queries are too difficult.
Every query looks for difference between the in the previous query found end time and the next start time. On the other hand this approach has a weaknes as well, I thought 15 steps would be enough (no more than 15 gaps expected), but this is not sure.
Can anyone give me a head start how this can be accomplished by an easier (and actual working) method? Maybe VBA?
Thx!
Art

Selecting Between Hours with Timestamp in SQL

I need to figure out how I can select the AVG from another column in a table, between two hour time intervals. I am using PL/SQL/Serverpages or PSP, so the user would select their interval of choice from a drop down menu (ex "2PM-4PM, 4PM-6PM",etc.) and then on the second page, using their choice I will provide information from another column in the table. The issue I have is that the format of my timestamp column is:
30-OCT-16 02.52.00.000000000 PM
30-OCT-16 02.54.00.000000000 PM
The way I have been trying to solve this problem is by using the following methodology:
IF number_text = 1 THEN
SELECT AVG(column) INTO avg_power
FROM table
WHERE date_column BETWEEN TO_DATE('12','HH') AND TO_DATE('2','HH')
AND LIKE '%PM';
I am going to use various IF statements in order to activate each select statement with the IF contingent on which interval the user selects from a drop down list.
As I said, the variable time depends on what the user selects on a prior page. My biggest issues in this situation are figuring out how I am supposed to code the WHERE clause as well as finding a way to work with the data, in terms of hours, as it exists in the database, while also taking AM and PM into account. I greatly appreciate any and all help to solve this issue.

SQL for Next/Prior Business Day from Calendar table (in MS Access)

I have a Calendar table pulled from our mainframe DBs and saved as a local Access table. The table has history back to the 1930s (and I know we use back to the 50s in at least one place), resulting in 31k records. This Calendar table has 3 fields of interest:
Bus_Dt - every day, not just business days. Primary Key
Bus_Day_Ind - indicates if the day was a valid business day for the stock market.
Prir_Bus_Dt - the prior business day. Contains some errors (about 50), all old.
I have written a query to retrieve the first business day on or after the current calendar day, but it runs supremely slowly. (5+ minutes) I have examined the showplan output and see it is being run via an x-join, which between 30k+ record tables gives a solution space (and date comparisons) in the order of nearly 10 million. However, the actual task is not hard, and could be preformed comfortably by excel in minimal time using a simple sort.
My question is thus, is there any way to fix the poor performance of the query, or is this an inherent failing of SQL? (DB2 run on the mainframe also is slow, though not crushingly so. Throwing cycles at the problem and all that.) Secondarily, if I were to trust prir_bus_dt, can I get there better? Or restrict the date range (aka, "cheat"), or any other tricks I didn't think of yet?
SQL:
SELECT TE2Clndr.BUS_DT AS Cal_Dt
, Min(TE2Clndr_1.BUS_DT) AS Next_Bus_Dt
FROM TE2Clndr
, TE2Clndr AS TE2Clndr_1
WHERE TE2Clndr_1.BUS_DAY_IND="Y" AND
TE2Clndr.BUS_DT<=[te2clndr_1].[bus_dt]
GROUP BY TE2Clndr.BUS_DT;
Showplan:
Inputs to Query
Table 'TE2Clndr'
Table 'TE2Clndr'
End inputs to Query
01) Restrict rows of table TE2Clndr
by scanning
testing expression "TE2Clndr_1.BUS_DAY_IND="Y""
store result in temporary table
02) Inner Join table 'TE2Clndr' to result of '01)'
using X-Prod join
then test expression "TE2Clndr.BUS_DT<=[te2clndr_1].[bus_dt]"
03) Group result of '02)'
Again, the question is, can this be made better (faster), or is this already as good as it gets?
I have a new query that is much faster for the same job, but it depends on the prir_bus_dt field (which has some errors). It also isn't great theory since prior business day is not necessarily available on everyone's calendar. So I don't consider this "the" answer, merely an answer.
New query:
SELECT TE2Clndr.BUS_DT as Cal_Dt
, Max(TE2Clndr_1.BUS_DT) AS Next_Bus_Dt
FROM TE2Clndr
INNER JOIN TE2Clndr AS TE2Clndr_1
ON TE2Clndr.PRIR_BUS_DT = TE2Clndr_1.PRIR_BUS_DT
GROUP BY TE2Clndr.BUS_DT;
What about this approach
select min(bus_dt)
from te2Clndr
where bus_dt >= date()
and bus_day_ind = 'Y'
This is my reference for date() representing the current date

Same dates from and to not showing data

the following is the sql being executed in my Crystal report.
There seems to be an issue with the same date request. Sometimes it shows data, other times not. We have data every day, we are a mass market company. Is there anything i can do for the sql to do select when from and to dates are the same?
SELECT "OEHIS1"."ODORD#", "OEHIS1"."ODORDT", "OEHIS1"."ODNTU$", "OEHIS1"."ODSHP#", "ICPRT1"."IARC11", "OEHIS1"."ODORDD", "ICPRT1"."IARCC4", "OEHIS1"."ODQTY#", "OEHIS1"."ODRQSD", "MFHHMH"."MHAWGT", "OEHIS1"."ODPRT#", "OEHIS1"."ODPRLC"
FROM ("S10M10"."ASTCCDTA"."EODDETAILS" "OEHIS1" INNER JOIN "S10M10"."ASTDTA"."ICPRT1" "ICPRT1" ON "OEHIS1"."ODPRT#"="ICPRT1"."IAPRT#") INNER JOIN "S10M10"."DLIB"."MFHHMH" "MFHHMH" ON "OEHIS1"."ODORD#"="MFHHMH"."MHORDP"
WHERE "OEHIS1"."ODPRT#" NOT LIKE 'FR%' AND "ICPRT1"."IARCC4"='FIN' AND "OEHIS1"."ODORDD"=20141027 AND NOT ("ICPRT1"."IARC11"='' OR "ICPRT1"."IARC11"='DRS') AND ("OEHIS1"."ODORDT"='CSA' OR "OEHIS1"."ODORDT"='CUS' OR "OEHIS1"."ODORDT"='INT' OR "OEHIS1"."ODORDT"='N4H' OR "OEHIS1"."ODORDT"='NFM' OR "OEHIS1"."ODORDT"='RTR') AND NOT ("OEHIS1"."ODPRLC" LIKE 'CMY%' OR "OEHIS1"."ODPRLC" LIKE 'DSC%' OR "OEHIS1"."ODPRLC" LIKE 'LGC%' OR "OEHIS1"."ODPRLC" LIKE 'X%')
ORDER BY "ICPRT1"."IARC11"
Migrated my comment to an answer, since that seemed to work for you.
I have very little CR experience, but with SQL you usually want to select between the day you want and the day after if you want results for today. That's because today, for example, is 10/27/2014, with no time. This defaults to midnight. If the date is the same on both sides, you'll only get results that happened at exactly midnight. Your query should be between 10/27/2014 and 10/28/2014 (midnight this morning to midnight tomorrow).

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").