DB2 select with different date format - sql

My problem is that in an ancient database there are two tables that I need to query for matching rows based on date. Only in one table date is represented as YYYYMM as a decimal(6) and in the other as YYYY-MM-DD as a date.
How do I join these two tables together?
I am perfectly happy searching on any day or day 01.

You can format that date as YYYYMM using TO_CHAR or VARCHAR_FORMAT, then join the two tables together.
Assuming table A has the date field in col1, and table B has the decimal(6) field in col2, it would look like this:
select *
from A
join B on dec(varchar_format(a.col1, 'YYYYMM'),6,0) = b.col2

You can perform join on those two tables. Suppose first table where date is stored as decimal(6) is A in column col1 and another table be B with date stored as column col2.The query would be something like below :
SELECT * FROM A, B
WHERE INT(A.col1) = INT(SUBSTR(B.col2,1,4)|| SUBSTR(B.col2,6,2))

Related

SQL - Join two tables based on a condition

I have an issue.
Table 1 ->
It has columns ID1 and Date1 (yyyymmdd) and Time1 (hh:mm:ss)
Table 2 ->
It has columns ID2 and Date2 (yyyymmdd hh:mm:ss)
None of the ID columns are unique.
What my first intention was, joining the tables on ID1=ID2 and date1 = cast (date2 as date)
and time1= cast(date2 as time).
However, I realized that time of Time1 and Date2 are not the same although they supposed to be.
Instead, I wanted to see what happens if I only joined using ID and date, excluding time.
With left join, I have only one extra row. That is because : I have more than one row in table 2
with the corresponding ID1 and Date1 values. Therefore join returns 2 rows instead of 1 row. BUT one of the time values in table1 and table2 actually match up.
To sum up :
I can't have the correct results when I join the tables by using ID,date, and time columns in table1.
I have one extra row when I join the tables by using only ID and date.
Is there any way that I can set up a condition -somewhere in the query-so that the query does the join by ID and date columns as a default but when this row duplication is a possibility, it will include time column, too?
I mean, I actually want to mix up "join on" and "case when".
I hope I could tell the problem understandable enough. Thank you all !

How can I create a dates-table inside a query in SQL Server?

Say I want to match records in table_a that have a startdate and an enddate to individual days and see if on, for instance March 13, one or more records in table_a match. I'd like to solve this by generating a row per day, with the date as the leading column, and any matching data from table_a as a left join.
I've worked with data warehouses that have date dimensions that make this job easy. But unfortunately I need to run this particular query on an OLTP database that doesn't have such a table.
How can I generate a row-per-day table in SQL Server? How can I do this inside my query, without temp tables, functions/procedures etc?
An alternative is a recursive query to generate the date series. Based on your pseudo-code:
with dates_table as (
select <your-start-date> dt
union all
select dateadd(day, 1, dt) from dates_table where dt < <your-end-date>
)
select d.dt, a.<whatever>
from dates_table d
left outer join table_a a on <join / date matching here>
-- where etc etc
option (maxrecursion 0)
I found a bit of a hack way to do this. I'll assume two years of dates is sufficient for your dates table.
Now, find a table in your database that has at least 800 records (365 x 2 + leap years - headache for multiplying 365 = ~~ 800). The question talks about selecting data from table_a, so we'll assume this is table_b. Then, create this Common Table Expression at the top of the query:
with dates_table as (
select top 800 -- or more/less if your timespan isn't ~2years
[date] = date_add(day, ROW_NUMBER() over (order by <random column>) -1, <your-start-date>)
from table_b
)
select d.[date]
, a.<whatever>
from dates_table d
left outer join table_a a on <join / date matching here>
-- where etc, etc, etc
Some notes:
This works by just getting the numbers 0 - 799 and adding them to an arbitrary date.
If you need more or less dates than two years, increase or decrease the number fed into the top statement. Ensure that table_b has sufficient rows: select count(*) from table_b.
<random column can be any column on table_b, the ordering doesn't matter. We're only interested in the numbers 1-800 ( -1 for a range of 0-799), but ROW_NUMBER requires an order by argument.
<your-start-date> has the first date tyou want in the dates table, and is included in the output.
in the where of the joined query, you could filter out any excess days that we overshot by taking 800 rows instead of 730 (+leap) by adding stuff like year(d.[date]) IN (2020, 2021).
If table_a has more than 800 records itself, this could be used as the basis for the dates_table instead of some other table too.

Select the max value on a multiple table join

I am trying to get the maximum date out of multiple tables when those table have a particular geometry.
My tables more or less look like that (of course they're all different but I shortened them in order to make it clearer ):
A table type :
Id, Info, Geometry, Date
And finally I have an other table that looks like that (shortened again) :
B table:
Id, Geometry
Now, what I want to do is to join all my A type tables on Geometry where they intersect with the B table Geometry, and to get the A table that has the most recent date.
I currently have the following request which is working:
UPDATE last_updateT SET date_last_update= S.dateMax
FROM
(SELECT B.gid, MAX(A.last_date) AS dateMax
FROM B
JOIN A ON ST_Intersects(B.geometry, A.geometry)
GROUP BY B.gid) S
WHERE T.id = S.gid;
Now I'd like to be able to do that kind of join on multiple table that looks like table A. I've heard of the function GREATEST but I am not sure about how to use it.
Also, I use Postgresql if that makes any differences.
It seems you are looking for UNION ALL, so you can treat the data from different tables as if it were data from only one table:
SELECT
b.gid,
MAX(x.last_date) AS dateMax
FROM b
JOIN
(
SELECT geometry, last_date FROM a
UNION ALL
SELECT geometry, last_date FROM aa
UNION ALL
SELECT geometry, last_date FROM aaa
) x ON ST_Intersects(b.geometry, x.geometry)
GROUP BY b.gid;
In broad strokes, MAX is an aggregate function, so you use MAX to get the highest value from the same column over a number of different rows.
GREATEST is a scalar function, you use GREATEST to get the highest value from different columns in the same row.
eg:
SELECT GREATEST(col1,col2,col3)
Greatest: https://www.postgresql.org/docs/9.5/static/functions-conditional.html
Max: https://www.postgresql.org/docs/9.5/static/functions-aggregate.html

SQL query searching a common field in all tables

All tables in a DB have the fields creationdate and revisiondate, which are date fields just as you'd think. Looking for a SQL query to find all instances where creationdate > '2017-02-01'. I'm not able to find an example where you loop through each table to return all new records as of X date in a DB. The DB has 1000 tables so I need to be able to search dynamically. The one table version of the query is (select * from tableA where creationdate > '2017-02-01') I just need to do that against all tables. Thanks!!!!
SELECT schema.column_1, schema.column2
FROM table_name_1
UNION
SELECT schema.column_same_datatype, schema.column2_same_datatype
FROM table_name_2
WHERE creation_date > '2017-02-01';
NOTE: YOu should have precaution about date format. I think the most common date format is DD-MM-YYYY.

Filling gaps in DATE fiel

I am querying a DATE field:
SELECT DATE ,
FIELD2 ,
FIELD3
into Table_new
FROM Table_old
WHERE (criteria iLIKE '%xxxyyy%')
The DATE field runs from 10/1/2010 to present, but it has missing days along the way. When I export the data (in Tableau, for example), I need the data to line up with a calendar that DOES NOT have any missing dates. This means I need a space/holder for a date, even if no data exists for that date in the query. How can I achieve this?
Right now I am exporting the data, and manually creating a space where no data for a date exists, which is extremely inefficient.
Tableau can do this natively. No need to alter your data set. You just need to make sure that your DATE field is of the date type in Tableau and then show emptycolumns/rows.
My test data:
Before I show empty columns:
How I show empty columns:
After I show empty columns (end result):
If you want to then restrict those dates, you can add the date field to the filter, select your date range, and Apply to Context.
In Postgres, you can easily generate the dates:
select mm.date, t.field1, t.field2
from (select generate_series(mm.mindate, mm.maxdate, interval '1 day') as date
from (select min(date) as mindate, max(date) as maxdate
from table_old
where criteria ilike '%xxxyyy%'
) mm
) d left join
table_old t
on t.date = mm.date and
criteria ilike '%xxxyyy%';
This returns all dates between the minimum and maximum for the criteria. If you have another date range in mind, just use that for the generate_series().
Note: The final condition on criteria needs to go in the on clause not a where clause.