Join two tables with not exactly matching dates in sql - sql

I have a table with dates that are about 1 month before the other table.
For example,
one table reports 1st quarter end on March 31st
and the other reports 1st quarter end on February 28th (or 29th)
but it would be perfectly fine to join them together by the date regardless that the two dates arent exactly the same.
Any suggestions, please.
Thanks

You can join on DateDiff(dd, Date1, Date2) < x
Or to get more exact
select endOfMonth.*, begOfMonth.*
from endOfMonth join begOfMonth
on DATEADD (dd , 1 , endOfMonth.date ) = begOfMonth.Date

Your ON clause could look at year and quarter for a match:
ON TABLE1.YEAR([1st quarter end ]) = TABLE2.YEAR([1st quarter end ])
AND TABLE1.QUARTER([1st quarter end ]) = TABLE2.QUARTER([1st quarter end ])

select val1 From Table1 T1 inner Join Table2 t2 on MONTH(T1.date1) = MONTH(t2.date1)
And YEAR(T1.date1) = YEAR(t2.date1)

One approach would be to use the DATEPART() function that returns the quarter for any given date. Then you would be able to join on the returned quarter.
Sample SQL:
SELECT *
FROM
(
SELECT DATEPART(QUARTER,date_column) AS t1_quarter
FROM table1
UNION ALL
SELECT DATEPART(QUARTER,date_column) AS t2_quarter
FROM table2
) AS temp
WHERE temp.t1_quarter = temp.t2_quarter;
Put any other fields as you require (ID fields most probably) in the internal SELECTS.

If I rigthly understood you and you have the same number of column in those tables then you should use UNION in your SQL-query. See more information about UNION here: http://en.wikipedia.org/wiki/Set_operations_%28SQL%29.

Related

SQL query that can create a row for skipped months

I have a table that I join to a calendar table, but I need to populate / create new row for each month between. I.e.
Date GIS CODE Running Total Open
2007-04-30 BEJOORDING, 6566, WESTERN AUSTRALIA 5
2007-09-30 BEJOORDING, 6566, WESTERN AUSTRALIA 6
I need some sort of query that can create end of month date rows between 2007-04-30 and 2007-09-30.
I will then need to fill down the blanks with the most recent fields so I will have a timeline for all end of month values.
I am assuming I will have to use some sort of CTE table but I am not the best at this / understand exactly how they work.
Any help will be greatly appreciated.
This CTE query will give you a table with all end-of-month values between the first and last ones in your table (I've assumed called log). You can then LEFT JOIN that to the table to create rows for all months in the timespan.
WITH CTE AS (
SELECT MIN(Date) AS [Date], MAX(Date) AS Max_Date FROM log
UNION ALL
SELECT EOMONTH(DATEADD(MONTH, 1, [Date])), Max_Date
FROM CTE
WHERE Date < Max_Date
)
SELECT Date
FROM CTE
Demo on SQLFiddle
Can be achieved with a RIGHT JOIN to a subquery against the calendar table using the EOMONTH() function

SQL Inner Join returns duplicates

I have the following 2 tables:
tab1 with 37146 rows
week_ref with 730 rows
All I want to do is join those tables on year and week so that the first week day and last week day will display next to the columns of the first table.
Below is my query:
SELECT tab1.year
,tab1.week
,tab1.col3
,tab1.col4
,tab1.col5
,tab1.col6
,tab1.total
,tab1.col7
,week_ref.first_week_day
,week_ref.last_week_day
FROM dtsetname.tab1
JOIN spyros.week_ref ON (week_ref.year = tab1.year AND week_ref.week = tab1.week)
The return of the query returns the 2 extra columns but the rows are 255535. So it is full of duplicates. I used to get how join works, but I guess not anymore xd... Any help on this? The correct output table should only give me 37146 rows since I only just want to add 2 extra columns.
Thanks
Below is for BigQuery Standard SQL
Before JOIN'ing you just need to dedup data in week_ref table as in below example
#standardSQL
SELECT tab1.year
,tab1.week
,tab1.col3
,tab1.col4
,tab1.col5
,tab1.col6
,tab1.total
,tab1.col7
,week_ref.first_week_day
,week_ref.last_week_day
FROM dtsetname.tab1 tab1
JOIN (SELECT DISTINCT year, week, first_week_day, last_week_day FROM spyros.week_ref) week_ref
ON (week_ref.year = tab1.year AND week_ref.week = tab1.week)
The problem is that your week_ref table has a row for each day rather than per week.
You can select just one day. If you have a weekday number or name (which I'm guessing that you do), that can be used:
FROM dtsetname.tab1 JOIN
spyros.week_ref wr
ON wr.year = tab1.year AND
wr.week = tab1.week AND
wr.dayname = 'Monday'
If such a column is not available, then you can either extract() the information or aggregate:
FROM dtsetname.tab1 JOIN
(SELECT ANY_VALUE(wr).*
FROM spyros.week_ref wr
GROUP BY wr.year, wr.week
) wr
ON wr.year = tab1.year AND
wr.week = tab1.week
first, I hope that year+week & year+day are primary keys in corresponding tables, otherwise the problem is there.
If so, here is another hint to check:
I notice that you join them by year and week, however, in the first table I see many 52 in a week column and in the second one 0 as a value.
There are only 52 weeks in year, plus a day, so is it possible you need to join by
week_ref.year = tab1.year AND week_ref.week = tab1.week+1
I think the solutions mentioned by others should work if you are looking to join to your reference table to get week start/end dates.
However, if you think your tab1 table has definite values in the week and year columns (and if I understand your data correctly) you can avoid the join altogether to get your desired results:
select
year
,week
,col3
,col4
,col5
,col6
,total
,col7
,date_sub(weekdate, interval IF(EXTRACT(DAYOFWEEK FROM weekdate) = 1, 6, EXTRACT(DAYOFWEEK FROM weekdate) - 1) day) as first_week_day
,date_add(date_sub(weekdate, interval IF(EXTRACT(DAYOFWEEK FROM weekdate) = 1, 6, EXTRACT(DAYOFWEEK FROM weekdate) - 1) day), interval 6 day) as last_week_day
from (
select
tab1.year
,tab1.week
,tab1.col3
,tab1.col4
,tab1.col5
,tab1.col6
,tab1.total
,tab1.col7
date_add(date(cast(tab1.year as int64), 1, 1), interval cast(tab1.week as int64) week) as weekdate
from `mydataset.tab1` as tab1
)
Hope it helps :)

How to select data of same date but previous year

How to select same data of previous year?
IN SQL Server use DATEADD:
SELECT a.ARRDate,
a.SomeData, --Current
b.SomeData --Previous
FROM MyTable a
LEFT JOIN MyTable b
ON DATEADD(year,-1,a.ARRDate) = b.ARRDate
Join your table with itself.

SQL to identify missing week

I have a database table with the following structure -
Week_End Sales
2009-11-01 43223.43
2009-11-08 4324.23
2009-11-15 64343.23
...
Week_End is a datetime column, and the date increments by 7 days with each new entry.
What I want is a SQL statement that will identify if there is a week missing in the sequence. So, if the table contained the following data -
Week_End Sales
2009-11-01 43223.43
2009-11-08 4324.23
2009-11-22 64343.73
...
The query would return 2009-11-15.
Is this possible? I am using SQL Server 2008, btw.
You've already accepted an answer so I guess you don't need this, but I was almost finished with it anyway and it has one advantage that the selected solution doesn't have: it doesn't require updating every year. Here it is:
SELECT T1.*
FROM Table1 T1
LEFT JOIN Table1 T2
ON T2.Week_End = DATEADD(week, 1, T1.Week_End)
WHERE T2.Week_End IS NULL
AND T1.Week_End <> (SELECT MAX(Week_End) FROM Table1)
It is based on Andemar's solution, but handles the changing year too, and doesn't require the existence of the Sales column.
Join the table on itself to search for consecutive rows:
select a.*
from YourTable a
left join YourTable b
on datepart(wk,b.Week_End) = datepart(wk,a.Week_End) + 1
-- No next week
where b.sales is null
-- Not the last week
and datepart(wk,a.Week_End) <> (
select datepart(wk,max(Week_End)) from YourTable
)
This should return any weeks without a next week.
Assuming your "week_end" dates are always going to be the Sundays of the week, you could try a CTE - a common table expression that lists out all the Sundays for 2009, and then do an outer join against your table.
All those rows missing from your table will have a NULL value for their "week_end" in the select:
;WITH Sundays2009 AS
(
SELECT CAST('20090104' AS DATETIME) AS Sunday
UNION ALL
SELECT
DATEADD(DAY, 7, cte.Sunday)
FROM
Sundays2009 cte
WHERE
DATEADD(DAY, 7, cte.Sunday) < '20100101'
)
SELECT
sun.Sunday 'Missing week end date'
FROM
Sundays2009 sun
LEFT OUTER JOIN
dbo.YourTable tbl ON sun.Sunday = tbl.week_end
WHERE
tbl.week_end IS NULL
I know this has already been answered, but can I suggest something really simple?
/* First make a list of weeks using a table of numbers (mine is dbo.nums(num), starting with 1) */
WITH AllWeeks AS (
SELECT DATEADD(week,num-1,w.FirstWeek) AS eachWeek
FROM
dbo.nums
JOIN
(SELECT MIN(week_end) AS FirstWeek, MAX(week_end) as LastWeek FROM yourTable) w
ON num <= DATEDIFF(week,FirstWeek,LastWeek)
)
/* Now just look for ones that don't exist in your table */
SELECT w.eachWeek AS MissingWeek
FROM AllWeeks w
WHERE NOT EXISTS (SELECT * FROM yourTable t WHERE t.week_end = w.eachWeek)
;
If you know the range you want to look over, you don't need to use the MIN/MAX subquery in the CTE.

Effective date statement where date spans multiple columns

I'm working on a DB2 database and trying to get records by effective date. The only catch is the effective date fields are spanned across 4 columns (month, day, century, year). I think I have the date piece figured out in the select but when I add the where clause I'm having problems. (note that I'm using the digits command to pad because the year 2005 yields just 5 in the year field)
select date(concat(digits(vsmo),concat('/',concat(digits(vsdy),
concat('/',concat(digits(vsct),digits(vsyr))))))) from
ddpincgr d
where (SELECT MAX(<NOT SURE WHAT TO PUT IN HERE>) FROM ddpincgr a WHERE a.vgrno = d.vgrno) <= date('1/1/2000')
Ideas?
Turn it into a sub-query
select *
from (select date(concat(digits(vsmo),concat('/',concat(digits(vsdy),
concat('/',concat(digits(vsct),digits(vsyr))))))) as myDate from
ddpincgr d) as myTable
where max(myTable.myDate) <= date('1/1/2000')
Can't you just put the entire concatenation in the select?
select date(concat(digits(vsmo),concat('/',concat(digits(vsdy), concat('/',concat(digits(vsct),digits(vsyr)))))))
from ddpincgr d
where ( SELECT MAX(date(concat(digits(vsmo),concat('/',concat(digits(vsdy), concat('/',concat(digits(vsct),digits(vsyr))))))))
FROM ddpincgr a
WHERE a.vgrno = d.vgrno) <= date('1/1/2000')