These below all relate to the same record in the same file....basically it is labelled 'UNK' until someone assigns a product number to it. in this case the number 12345678 was assigned by Paul on 01Jan. Each record before/after that is when someone changes something on that record.
What I want is to capture that record, the 1st time when it goes from UNK to a number... and capture the user name and date etc from that line.
I have tried min, least, and I'm not sure about rownum or where to put the string if I did.
Car_Id Product # user name date
111 unk john 20Dec
111 unk alan 25Dec
111 unk pete 30Dec
111 12345678 paul 01Jan
111 12345678 jim 10Jan
222 unk alan 25Dec
222 unk pete 30Dec
222 87654321 paul 02Jan
222 87654321 steve 05Jan
But in logical terms I want it to do this... give me the 1st record after UNK.
Please can I have the full string if possible.
Correct me if I am wrong, but your data seems to be ordered by date, so logically you could just take the first recoredset where the productnumber is not "unk".
Select *
From (SELECT * FROM YourTable orderby date) t -- make sure data is ordered before selecting it
where t.ProductNr <> 'unk' and -- don't get data without a number
rownum = 1 -- take the first
Sounds like maybe the analytic function row_number() would be the best way to do this:
with sample_data as (select 111 car_id, 'unk' product#, 'john' user_name, to_date('20/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 111 car_id, 'unk' product#, 'alan' user_name, to_date('21/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 111 car_id, 'unk' product#, 'pete' user_name, to_date('22/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 111 car_id, '12345678' product#, 'paul' user_name, to_date('23/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 111 car_id, '12345678' product#, 'jim' user_name, to_date('24/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 222 car_id, 'unk' product#, 'alan' user_name, to_date('25/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 222 car_id, 'unk' product#, 'pete' user_name, to_date('26/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 222 car_id, '87654321' product#, 'paul' user_name, to_date('27/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual union all
select 222 car_id, '87654321' product#, 'steve' user_name, to_date('28/12/2014 10:12:24', 'dd/mm/yyyy hh24:mi:ss') dt from dual)
select car_id,
product#,
user_name,
dt
from (select sd.*,
row_number() over (partition by car_id order by dt) rn
from sample_data sd
where product# != 'unk')
where rn = 1;
CAR_ID PRODUCT# USER_NAME DT
---------- -------- --------- ---------------------
111 12345678 paul 23/12/2014 10:12:24
222 87654321 paul 27/12/2014 10:12:24
Related
I have a table with customers, purchase date and zip code. Key is (customer_id, purchase_dt and zip_cd)
I am trying to find zip codes where customers are doing business, ranges like 80% and above, 60 - 80%, 40-60%. Can someone help me out with a query to achieve this.
with tmp as
(
select 123 as cust_id, date '2017-01-01' purchase_dt, '10035' zip_cd from dual
union
select 1234 as cust_id, date '2019-06-01' purchase_dt, '11377' zip_cd from dual
union
select 12345 as cust_id, date '2019-07-01' purchase_dt, '11377' zip_cd from dual
union
select 234 as cust_id, date '2019-08-01' purchase_dt, '11377' zip_cd from dual
union
select 2345 as cust_id, date '2019-09-01' purchase_dt, '11417' zip_cd from dual
)
select * from tmp;
Expected output:
80% and above zip code: 11377 and so on..
You can use the combination of the average and analytical function count as follows:
with tmp as
(
select 123 as cust_id, date '2017-01-01' purchase_dt, '10035' zip_cd from dual
union
select 1234 as cust_id, date '2019-06-01' purchase_dt, '11377' zip_cd from dual
union
select 12345 as cust_id, date '2019-07-01' purchase_dt, '11377' zip_cd from dual
union
select 234 as cust_id, date '2019-08-01' purchase_dt, '11377' zip_cd from dual
union
select 2345 as cust_id, date '2019-09-01' purchase_dt, '11417' zip_cd from dual
)
select zip_cd, 100*(count(1)/cnt) percntg from
(select zip_cd, count(1) over () cnt from tmp)
group by zip_cd, cnt
order by percntg desc;
This answer will take into account if a customer has made purchases on multiple days and won't double count them. Additionally, this response adds in the grouping discussed in the question:
with tmp as
(
select 123 as cust_id, date '2017-01-01' purchase_dt, '10035' zip_cd from dual
union
select 1234 as cust_id, date '2019-06-01' purchase_dt, '11377' zip_cd from dual
union
select 12345 as cust_id, date '2019-07-01' purchase_dt, '11377' zip_cd from dual
union
select 234 as cust_id, date '2019-08-01' purchase_dt, '11377' zip_cd from dual
union
select 2345 as cust_id, date '2019-09-01' purchase_dt, '11417' zip_cd from dual
)
SELECT sub2.pct_range, listagg(sub2.zip_cd||' ('||sub2.zip_pct||')', ', ') WITHIN GROUP (ORDER BY zip_pct DESC) AS ZIP_CODES
FROM (SELECT CASE
WHEN sub.zip_pct BETWEEN 80 AND 100 THEN '80% and above'
WHEN sub.zip_pct BETWEEN 60 AND 79 THEN '60% to 79%'
WHEN sub.zip_pct BETWEEN 40 AND 59 THEN '40% to 59%'
WHEN sub.zip_pct BETWEEN 20 AND 39 THEN '20% to 39%'
ELSE 'Below 20%'
END AS PCT_RANGE,
sub.zip_cd,
sub.zip_pct
FROM (SELECT DISTINCT
zip_cd,
100*COUNT(DISTINCT cust_id) OVER (PARTITION BY zip_cd)/COUNT(DISTINCT cust_id) OVER () AS ZIP_PCT
FROM tmp) sub) sub2
GROUP BY pct_range
ORDER BY pct_range DESC;
I have the below table. I need to count how many ids were active in a given month. So thinking I'll need to create a row for each id that was active during that month so that id can be counted each month. A row should be generated for a term_dt during that month.
active_dt term_dt id
1/1/2018 101
1/1/2018 5/15/2018 102
3/1/2018 6/1/2018 103
1/1/2018 4/25/18 104
Apparently this is a "count number of overlapping intervals" problem. The algorithm goes like this:
Create a sorted list of all start and end points
Calculate a running sum over this list, add one when you encounter a start and subtract one when you encounter an end
If two points are same then perform subtractions first
You will end up with list of all points where the sum changed
Here is a rough outline of the query. It is for SQL Server but could be ported to any RDBMS that supports window functions:
WITH cte1(date, val) AS (
SELECT active_dt, 1 FROM #t AS t
UNION ALL
SELECT COALESCE(term_dt, '2099-01-01'), -1 FROM #t AS t
-- if end date is null then assume the row is valid indefinitely
), cte2 AS (
SELECT date, SUM(val) OVER(ORDER BY date, val) AS rs
FROM cte1
)
SELECT YEAR(date) AS YY, MONTH(date) AS MM, MAX(rs) AS MaxActiveThisYearMonth
FROM cte2
GROUP BY YEAR(date), MONTH(date)
DB Fiddle
I was toying with a simpler query, that seemed to do the trick, for Oracle:
with candidates (month_start) as (
select to_date ('2018-' || column_value || '-01','YYYY-MM-DD')
from
table
(sys.odcivarchar2list('01','02','03','04','05',
'06','07','08','09','10','11','12'))
), sample_data (active_dt, term_dt, id) as (
select to_date('01/01/2018', 'MM/DD/YYYY'), null, 101 from dual
union select to_date('01/01/2018', 'MM/DD/YYYY'),
to_date('05/15/2018', 'MM/DD/YYYY'), 102 from dual
union select to_date('03/01/2018', 'MM/DD/YYYY'),
to_date('06/01/2018', 'MM/DD/YYYY'), 103 from dual
union select to_date('01/01/2018', 'MM/DD/YYYY'),
to_date('04/25/2018', 'MM/DD/YYYY'), 104 from dual
)
select c.month_start, count(1)
from candidates c
join sample_data d
on c.month_start between d.active_dt and nvl(d.term_dt,current_date)
group by c.month_start
order by c.month_start
An alternative solution would be to use a hierarchical query, e.g.:
WITH your_table AS (SELECT to_date('01/01/2018', 'dd/mm/yyyy') active_dt, NULL term_dt, 101 ID FROM dual UNION ALL
SELECT to_date('01/01/2018', 'dd/mm/yyyy') active_dt, to_date('15/05/2018', 'dd/mm/yyyy') term_dt, 102 ID FROM dual UNION ALL
SELECT to_date('01/03/2018', 'dd/mm/yyyy') active_dt, to_date('01/06/2018', 'dd/mm/yyyy') term_dt, 103 ID FROM dual UNION ALL
SELECT to_date('01/01/2018', 'dd/mm/yyyy') active_dt, to_date('25/04/2018', 'dd/mm/yyyy') term_dt, 104 ID FROM dual)
SELECT active_month,
COUNT(*) num_active_ids
FROM (SELECT add_months(TRUNC(active_dt, 'mm'), -1 + LEVEL) active_month,
ID
FROM your_table
CONNECT BY PRIOR ID = ID
AND PRIOR sys_guid() IS NOT NULL
AND LEVEL <= FLOOR(months_between(coalesce(term_dt, SYSDATE), active_dt)) + 1)
GROUP BY active_month
ORDER BY active_month;
ACTIVE_MONTH NUM_ACTIVE_IDS
------------ --------------
01/01/2018 3
01/02/2018 3
01/03/2018 4
01/04/2018 4
01/05/2018 3
01/06/2018 2
01/07/2018 1
01/08/2018 1
01/09/2018 1
01/10/2018 1
Whether this is more or less performant than the other answers is up to you to test.
I'm having troubles retrieving balance information from my table. Dataset looks like this:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | $1600 | 2017-01-01 |
| John | Doe | $12 | 2017-01-02 |
| John | Doe | $1 | 2017-01-03 |
| John | Doe | $16 | 2017-01-04 |
| John | Doe | $16 | 2017-01-05 |
| John | Doe | $16 | 2017-01-06 |
The task is to get most recent Balance with Update Date, but if same Balance is the same for several days, then in that case we need to get first Update Date with this Balance, so in that case, we need the following result:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | $16 | 2017-01-04 |
I tried to use my query:
select
a.name,
a.last_name,
a.balance,
a.update_date
from
(select
name,
last_name,
balance,
update_date,
rank () over (partition by name, last_name order by update_date desc) top
from
customer_balance) a
where
a.top = 1
but it obviously returns:
| Name | Last Name | Balance | Update Date |
+---------------+---------------+---------+-------------+
| John | Doe | $16 | 2017-01-06 |
I'm not sure how to modify it to get desired result. Please note that I have limited access so no temp tables, functions or anything like that is allowed. Just plain selects, nothing fancy.
I'd appreciate your help.
You can do this by using Tabibitosan to find the group of rows with the same balance that contains the latest update_date row (the difference between the rows at the top of the whole dataset and the latest balance will be 0) and then a group by to pick the earliest update_date, like so:
WITH customer_balance AS (SELECT 'John' first_name, 'Doe' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 15 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe2' last_name, 16 balance, to_date('07/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 1600 balance, to_date('01/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 12 balance, to_date('02/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 1 balance, to_date('03/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('04/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('05/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 16 balance, to_date('06/01/2017', 'dd/mm/yyyy') update_date FROM dual UNION ALL
SELECT 'John' first_name, 'Doe3' last_name, 17 balance, to_date('07/01/2017', 'dd/mm/yyyy') update_date FROM dual)
SELECT first_name,
last_name,
balance,
min(update_date) update_date
FROM (SELECT first_name,
last_name,
balance,
update_date,
row_number() OVER (PARTITION BY first_name, last_name ORDER BY update_date DESC) -- row number across the entire dataset (i.e. for each first_name and last_name)
- row_number() OVER (PARTITION BY first_name, last_name, balance ORDER BY update_date DESC) grp -- row number across each balance in the entire dataset.
FROM customer_balance)
WHERE grp = 0
GROUP BY first_name,
last_name,
balance;
FIRST_NAME LAST_NAME BALANCE UPDATE_DATE
---------- --------- ---------- -----------
John Doe 16 04/01/2017
John Doe2 16 06/01/2017
John Doe3 17 07/01/2017
I've provided 3 scenarios:
Where the latest rows are for the same balance but that balance doesn't occur earlier in the dataset (i.e. your original dataset)
The latest rows are for the same balance but that balance occurs earlier in the dataset
The latest row has a different balance to the previous row.
Maybe you could try this query
WITH bal AS
(SELECT 'John' first_name,
'Doe' last_name,
1600 balance,
to_date('20170101', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
12 balance,
to_date('20170102', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
1 balance,
to_date('20170103', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170104', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170105', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
16 balance,
to_date('20170106', 'YYYYMMDD') update_date
FROM dual
UNION ALL SELECT 'John',
'Doe',
328 balance,
to_date('20170107', 'YYYYMMDD') update_date
FROM dual) -- The main query
SELECT *
FROM
(SELECT bal.*,
LAG(balance) OVER(PARTITION BY first_name, last_name
ORDER BY update_date)prev_balance
FROM bal )
WHERE prev_balance IS NULL
OR balance != prev_balance
In the first step we get the previous balance.
At the second one we remove all lines where previous balance equals current one.
BTW sorry for the layout I answered from my smartphone.
I don't have time to write out a tested solution, but the analytic function lead() and lag() are intended for this:
select name, last_name, balance, update_date
from (select name,
last_name,
balance,
update_date,
lead(balance) over (partition by first_name, last_name
order by update_date)
as next_balance
where balance = :target_balance
order by update_date
)
where balance <> next_balance
and rownum = 1
I am trying to select a record from a row by looking at both the start date and the end date. What I need to do is pick the max start date, then only return a result from that max date if the end date has a value.
I hope the images below help clarify this a bit more. This is in Oracle based SQL.
Example #2
I can, so far, either return all the records or incorrectly return a record in scenario #2 but I've yet to figure out the best way to make this work. I would greatly appreciate any assistance.
Thank you!
I would use an analytic function:
with sample_data as (select 1 id, 1 grp_id, to_date('01/01/2015', 'dd/mm/yyyy') st_dt, to_date('23/01/2015', 'dd/mm/yyyy') ed_dt from dual union all
select 2 id, 1 grp_id, to_date('24/02/2015', 'dd/mm/yyyy') st_dt, to_date('15/02/2015', 'dd/mm/yyyy') ed_dt from dual union all
select 3 id, 1 grp_id, to_date('17/03/2015', 'dd/mm/yyyy') st_dt, to_date('30/03/2015', 'dd/mm/yyyy') ed_dt from dual union all
select 4 id, 2 grp_id, to_date('01/01/2015', 'dd/mm/yyyy') st_dt, to_date('17/01/2015', 'dd/mm/yyyy') ed_dt from dual union all
select 5 id, 2 grp_id, to_date('21/01/2015', 'dd/mm/yyyy') st_dt, to_date('23/03/2015', 'dd/mm/yyyy') ed_dt from dual union all
select 6 id, 2 grp_id, to_date('14/04/2015', 'dd/mm/yyyy') st_dt, to_date('16/05/2015', 'dd/mm/yyyy') ed_dt from dual union all
select 7 id, 2 grp_id, to_date('28/05/2015', 'dd/mm/yyyy') st_dt, null ed_dt from dual),
res as (select id,
grp_id,
st_dt,
ed_dt,
max(st_dt) over (partition by grp_id) max_st_dt
from sample_data)
select id,
grp_id,
st_dt,
ed_dt
from res
where st_dt = max_st_dt
and ed_dt is not null;
ID GRP_ID ST_DT ED_DT
---------- ---------- ---------- ----------
3 1 17/03/2015 30/03/2015
This would be one of the simplest way.
select * from
(
select apay_id,
max(start_dt) OVER () max_start_dt,
start_dt,
end_dt
from sample
)
where
start_dt=max_start_dt
and end_dt is not null
Idea is to get maximum start_dt and corresponding end_dt.
And then filter result if end_dt is null.
SQL Fiddle
Database Schema
create table sample
(apay_id number(7),
account_number number(7),
start_dt date,
end_dt date);
Sample1
insert into sample values(554433, 123456, '15-Aug-15', null);
insert into sample values(112266, 123456, '21-Jul-15', '31-Aug-15');
insert into sample values(733221, 123456, '29-Jun-15', '31-Jul-15');
Output for Sample1
No rows
Sample2
insert into sample values(554433, 123456, '15-Aug-15', '11-Nov-15');
insert into sample values(112266, 123456, '21-Jul-15', '31-Aug-15');
insert into sample values(733221, 123456, '29-Jun-15', '31-Jul-15');
Output for Sample2
| APAY_ID | MAX_START_DT | END_DT |
|---------|--------------------------|----------------------------|
| 554433 | August, 15 2015 00:00:00 | November, 11 2015 00:00:00 |
select * from ( select apay_id from sample where end_dt is not null order by start_dt desc) where rownum=1
I think this can also work.
I'm trying to figure out a way of identifying a "run" of results (successive rows, in order) that meet some condition. Currently, I'm ordering a result set, and scanning by eye for particular patterns. Here's an example:
SELECT the_date, name
FROM orders
WHERE
the_date BETWEEN
to_date('2013-09-18',..) AND
to_date('2013-09-22', ..)
ORDER BY the_date
--------------------------------------
the_date | name
--------------------------------------
2013-09-18 00:00:01 | John
--------------------------------------
2013-09-19 00:00:01 | James
--------------------------------------
2013-09-20 00:00:01 | John
--------------------------------------
2013-09-20 00:00:02 | John
--------------------------------------
2013-09-20 00:00:03 | John
--------------------------------------
2013-09-20 00:00:04 | John
--------------------------------------
2013-09-21 16:00:01 | Jennifer
--------------------------------------
What I want to extract from this result set is all the rows attributed to John on 2013-09-20. Generally what I'm looking for is a run of results from the same name, in a row, >= 3. I'm using Oracle 11, but I'm interested to know if this can be achieved with strict SQL, or if some kind of analytical function must be used.
You need multiple nested window functions:
SELECT *
FROM
(
SELECT the_date, name, grp,
COUNT(*) OVER (PARTITION BY grp) AS cnt
FROM
(
SELECT the_date, name,
SUM(flag) OVER (ORDER BY the_date) AS grp
FROM
(
SELECT the_date, name,
CASE WHEN LAG(name) OVER (ORDER BY the_date) = name THEN 0 ELSE 1 END AS flag
FROM orders
WHERE
the_date BETWEEN
TO_DATE('2013-09-18',..) AND
TO_DATE('2013-09-22', ..)
) dt
) dt
) dt
WHERE cnt >= 3
ORDER BY the_date
Try this
WITH ORDERS
AS (SELECT
TO_DATE ( '2013-09-18 00:00:01',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'John' AS NAME
FROM
DUAL
UNION ALL
SELECT
TO_DATE ( '2013-09-19 00:00:01',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'James' AS NAME
FROM
DUAL
UNION ALL
SELECT
TO_DATE ( '2013-09-20 00:00:01',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'John' AS NAME
FROM
DUAL
UNION ALL
SELECT
TO_DATE ( '2013-09-20 00:00:02',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'John' AS NAME
FROM
DUAL
UNION ALL
SELECT
TO_DATE ( '2013-09-20 00:00:03',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'John' AS NAME
FROM
DUAL
UNION ALL
SELECT
TO_DATE ( '2013-09-20 00:00:04',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'John' AS NAME
FROM
DUAL
UNION ALL
SELECT
TO_DATE ( '2013-09-21 16:00:01',
'YYYY-MM-DD HH24:MI:SS' )
AS THE_DATE,
'Jennifer' AS NAME
FROM
DUAL)
SELECT
B.*
FROM
(SELECT
TRUNC ( THE_DATE ) THE_DATE,
NAME,
COUNT ( * )
FROM
ORDERS
WHERE
THE_DATE BETWEEN TRUNC ( TO_DATE ( '2013-09-18',
'YYYY-MM-DD' ) )
AND TRUNC ( TO_DATE ( '2013-09-22',
'YYYY-MM-DD' ) )
GROUP BY
TRUNC ( THE_DATE ),
NAME
HAVING
COUNT ( * ) >= 3) A,
ORDERS B
WHERE
A.NAME = B.NAME
AND TRUNC ( A.THE_DATE ) = TRUNC ( B.THE_DATE );
OUTPUT
9/20/2013 12:00:01 AM John
9/20/2013 12:00:02 AM John
9/20/2013 12:00:03 AM John
9/20/2013 12:00:04 AM John