case statement in Where clause issue - sql

I have quite a Query to write.
I have a File called FG500 which has a field called UTXT(Certification number). The key(Not Unique) for the file is Model Number(MODL).The file can have multiple rows with the model numbers. It has also create date(CRDT), create time(CRTM), change date(CHDT), Change time(CHTM)
I need to pull latest EU Certification Number(UTXT) based on Create Date& Time / Change Date& Time. That is, if the change date/Time is not 0, then pull the latest of that.. Else check the create date and pull the latest record from that.
I will have to use a case but not sure how. Any help is highly appreciated.
Sample Data:
Model Number L12G4AGAEA L12G4AGAEA
UTXT (Blank) E4*2002/24*0458
Create date 07/30/12 03/16/12
Create Time 08:32:22 08:32:22
Change Date 07/31/12 03/17/12
Change Time 08:32:22 08:32:22
Expected result would be a Blank as the highest change date/Time is the first record. Had the change date been blank, then I would go ahead with the create date/Time

Perhaps this will assist. I built the table from your first set of tabular data, and the query demonstrates use of ROW_NUMBER() to arrive at the "latest" row for each modelnumber. I have used MS SQL Server from this example as the query syntax for DB2 is similar.
This might not be a complete answer, and as I don't have access to DB2 I'm not able to demonstrate how to combine the date and time columns which really should be done.
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Table1
([ModelNumber] varchar(10), [UTXT] varchar(15), [CREATEdate] datetime, [CREATEtime] varchar(8), [CHANGEdate] datetime, [CHANGEtime] varchar(8))
;
INSERT INTO Table1
([ModelNumber], [UTXT], [CREATEdate], [CREATEtime], [CHANGEdate], [CHANGEtime])
VALUES
('L12G4AGAEA', NULL, '2012-07-30 00:00:00', '08:32:22', '2012-07-31 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-03-16 00:00:00', '08:32:22', '2012-03-17 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-07-11 00:00:00', '08:32:22', '2012-07-12 00:00:00', '08:32:22'),
('L12G4AGAEA', NULL, '2012-07-25 00:00:00', '08:32:22', '2012-07-26 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-07-11 00:00:00', '08:32:22', '2012-07-12 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-05-22 00:00:00', '08:32:22', '2012-05-23 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-08-03 00:00:00', '08:32:22', '2012-08-03 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-05-22 00:00:00', '08:32:22', '2012-05-23 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-05-15 00:00:00', '08:32:22', '2012-05-16 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-07-20 00:00:00', '08:32:22', '2012-07-21 00:00:00', '08:32:22'),
('L12G4AGAEA', 'E4*2002/24*0458', '2012-05-11 00:00:00', '08:32:22', '2012-05-14 00:00:00', '08:32:22')
;
Query 1:
select
*
from (
select
*
, row_number() over(partition by ModelNumber
order by coalesce(CHANGEdate,CREATEdate) DESC) rn
from table1
) d
where rn = 1
Results:
| ModelNumber | UTXT | CREATEdate | CREATEtime | CHANGEdate | CHANGEtime | rn |
|-------------|-----------------|----------------------|------------|----------------------|------------|----|
| L12G4AGAEA | E4*2002/24*0458 | 2012-08-03T00:00:00Z | 08:32:22 | 2012-08-03T00:00:00Z | 08:32:22 | 1 |

Related

How do I merge two SELECT queries with different WHERE clauses

I'm trying to write query on two different selects with different WHERE clause and using GROUP BY.
I browsed for examples but mine is different since I have multiple fields for SELECT.
Here is example data:
-- drop table #temp_counts;
create table #temp_counts(
report_date smalldatetime not null,
Emp_id varchar(10) not null,
source_system varchar(10) not null
)
Insert into #temp_counts values ('2021-05-02 00:00:00', '12411', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '56421', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '45411', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '75411', 'ABC');
Insert into #temp_counts values ('2021-05-02 00:00:00', '13245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '66245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '77245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '98245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '34245', 'XYZ');
Insert into #temp_counts values ('2021-05-02 00:00:00', '29245', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '14524', 'ABC');
Insert into #temp_counts values ('2021-05-03 00:00:00', '17824', 'ABC');
Insert into #temp_counts values ('2021-05-03 00:00:00', '32524', 'ABC');
Insert into #temp_counts values ('2021-05-03 00:00:00', '16724', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '19924', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '89424', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '48324', 'XYZ');
Insert into #temp_counts values ('2021-05-03 00:00:00', '16000', 'XYZ');
Insert into #temp_counts values ('2021-05-04 00:00:00', '18724', 'ABC');
Insert into #temp_counts values ('2021-05-04 00:00:00', '12904', 'XYZ');
Insert into #temp_counts values ('2021-05-05 00:00:00', '12074', 'ABC');
Insert into #temp_counts values ('2021-05-05 00:00:00', '12784', 'XYZ');
Insert into #temp_counts values ('2021-05-05 00:00:00', '12324', 'XYZ');
Insert into #temp_counts values ('2021-05-05 00:00:00', '75124', 'XYZ');
These are the queries I would like to merge:
select count(*) emp_count, report_date , 'ABC' source_system from #temp_counts
where source_system = 'ABC'
group by report_date
order by report_date
select count(*) emp_count, report_date , 'XYZ' source_system from #temp_counts
where source_system = 'XYZ'
group by report_date
order by report_date
I tried 2 methods as under:
--Method 1
select fir.emp_count, fir.report_date, fir.source_system from
(select count(*) emp_count, report_date , 'ABC' source_system from #temp_counts
where source_system = 'ABC') as fir
inner join
(select count(*) emp_count, report_date , 'XYZ' source_system from #temp_counts
where source_system = 'XYZ') as sec
on fir.report_date = sec.report_date
group by fir.report_date
order by fir.report_date
--Method 2
select count(*) emp_count, report_date , 'ABC' source_system from #temp_counts
where source_system = 'ABC'
UNION ALL
select count(*) emp_count, report_date , 'XYZ' source_system from #temp_counts
where source_system = 'XYZ'
group by report_date
order by report_date
Both give Error:
Msg 8120, Level 16, State 1, Line 61
Column '#temp_counts.report_date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Please guide
seems like you just want to group by report_date and source_system:
select count(*) emp_count, report_date , source_system
FROM #temp_counts
group by report_date, source_system
order by source_system,report_date
if you want to have result for specific source systems then you can combine conditions:
select count(*) emp_count, report_date , source_system
FROM #temp_counts
where source_system in ('ABC', 'XYZ')
group by report_date, source_system
order by source_system,report_date
you can change order by to show rows in the order you want to show
just to illustrate how to use union :
select count(*) emp_count, report_date , source_system from #temp_counts
where source_system = 'ABC'
group by report_date
union all
select count(*) emp_count, report_date , source_system from #temp_counts
where source_system = 'XYZ'
group by report_date
order by source_system, report_date

SQL window function with date condition not returning expected value

I want to find the maximum value before the current date but within 1 year of a value using a window function. My attempt is not giving me the correct value and not sure why?
[MaxPrevious] is the desired result
[MaxPrevious2] is the window function result with the wrong value.
I need to use a window function as the final query is more complex but the date condition part is not working.
Desired Output:
Full table data and query:
--DROP TABLE [dbDelete].[dbo].[tblData]
--CREATE TABLE [dbDelete].[dbo].[tblData]
--([Date] datetime, [Part] varchar(10), [Tolerance] float);
--INSERT INTO [dbDelete].[dbo].[tblData] ([Date], [Part], [Tolerance])
--VALUES
--('2012-01-19 00:00:00', 'X1', 6.8),
--('2011-12-15 00:00:00', 'X1', 6.7),
--('2011-10-25 00:00:00', 'X1', 7.8),
--('2010-05-06 00:00:00', 'X1', 8.3),
--('2010-04-13 00:00:00', 'X1', 7.2),
--('2010-01-21 00:00:00', 'X1', 4.7),
--('2009-12-28 00:00:00', 'X1', 6.9),
--('2009-01-01 00:00:00', 'X1', 7.8),
--('2008-11-16 00:00:00', 'X1', 7.4),
--('2008-11-08 00:00:00', 'X1', 7.9),
--('2012-01-19 00:00:00', 'X2', 3.8),
--('2011-12-15 00:00:00', 'X2', 3.7),
--('2011-10-25 00:00:00', 'X2', 4.8),
--('2010-05-06 00:00:00', 'X2', 5.3),
--('2010-04-13 00:00:00', 'X2', 4.2),
--('2010-01-21 00:00:00', 'X2', 1.7),
--('2009-12-28 00:00:00', 'X2', 3.9),
--('2009-01-01 00:00:00', 'X2', 4.8),
--('2008-11-16 00:00:00', 'X2', 4.4),
--('2008-11-08 00:00:00', 'X2', 4.9)
--;
select t1.*
-- Find max before current record but within 1 year
,(select top (1) t2.[Tolerance] from [dbDelete].[dbo].[tblData] t2
where t2.[Date] < t1.[Date]
and t2.[Date] >= dateadd(year, -1, t1.[Date])
and t2.[Part] = t1.[Part]
order by t2.[Tolerance] desc) as [MaxPrevious]
-- Find max before current record but within 1 year
,max(case when t1.[Date] >= dateadd(year, -1, t1.[Date]) then t1.[Tolerance] else 0 end) over
(partition by t1.[Part]
order by t1.[Date]
rows between unbounded preceding and 1 preceding
) as [MaxPrevious2]
from [dbDelete].[dbo].[tblData] t1
order by t1.[Part], t1.[Date] desc
--DROP TABLE [dbDelete].[dbo].[tblData]
--CREATE TABLE [dbDelete].[dbo].[tblData]
--([Date] datetime, [Part] varchar(10), [Tolerance] float);
--INSERT INTO [dbDelete].[dbo].[tblData] ([Date], [Part], [Tolerance])
--VALUES
--('2012-01-19 00:00:00', 'X1', 6.8),
--('2011-12-15 00:00:00', 'X1', 6.7),
--('2011-10-25 00:00:00', 'X1', 7.8),
--('2010-05-06 00:00:00', 'X1', 8.3),
--('2010-04-13 00:00:00', 'X1', 7.2),
--('2010-01-21 00:00:00', 'X1', 4.7),
--('2009-12-28 00:00:00', 'X1', 6.9),
--('2009-01-01 00:00:00', 'X1', 7.8),
--('2008-11-16 00:00:00', 'X1', 7.4),
--('2008-11-08 00:00:00', 'X1', 7.9),
--('2012-01-19 00:00:00', 'X2', 3.8),
--('2011-12-15 00:00:00', 'X2', 3.7),
--('2011-10-25 00:00:00', 'X2', 4.8),
--('2010-05-06 00:00:00', 'X2', 5.3),
--('2010-04-13 00:00:00', 'X2', 4.2),
--('2010-01-21 00:00:00', 'X2', 1.7),
--('2009-12-28 00:00:00', 'X2', 3.9),
--('2009-01-01 00:00:00', 'X2', 4.8),
--('2008-11-16 00:00:00', 'X2', 4.4),
--('2008-11-08 00:00:00', 'X2', 4.9)
--;
;with cte as (
select DATEADD(year, -1, [Date]) as PrevDate, * from [dbDelete].[dbo].[tblData]
)
select b.[Date], b.Part, b.Tolerance, max(a.Tolerance) as MaxPrevious from cte a
right join cte b
on a.Part = b.Part and a.[Date] >= b.[PrevDate] and a.[Date] < b.[Date]
group by b.[Date], b.Part, b.Tolerance
order by b.[Part], b.[Date] desc
I am not sure if this is doable by using just a window functions.

Calculate difference in hours/days between different actions by a same user sql

I have a table where users perform an order action. I want to get difference in dates between his two or more orders. And similar for all users and then calculate their average or median.
Another issue is the order rows are duplicates because of another column in the table called order_received time which are 5 secs apart due to this two rows are created for the same users with same order time.
Based on your comment on my initial answer here is another worksheet.
Table DDL
create table tbl_order(
order_id integer,
account_number integer,
ordered_at date
);
Data as in other thread you pointed out
insert into tbl_order values (1, 1001, to_date('10-Sep-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (2, 2001, to_date('01-Sep-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (3, 2001, to_date('03-Sep-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (4, 1001, to_date('12-Sep-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (5, 3001, to_date('18-Sep-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (6, 1001, to_date('20-Sep-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
Query
WITH VW AS (
SELECT ACCOUNT_NUMBER,
MIN(ORDERED_AT) EARLIEST_ORDER_AT,
MAX(ORDERED_AT) LATEST_ORDER_AT,
ROUND(MAX(ORDERED_AT) - MIN(ORDERED_AT), 5) DIFF_IN_DAYS,
COUNT(*) TOTAL_ORDER_COUNT
FROM TBL_ORDER
GROUP BY ACCOUNT_NUMBER
)
SELECT ACCOUNT_NUMBER, EARLIEST_ORDER_AT, LATEST_ORDER_AT,
DIFF_IN_DAYS, ROUND( DIFF_IN_DAYS/TOTAL_ORDER_COUNT, 4) AVERAGE
FROM VW;
Result
===========Initial answer hereafter===========
Your question is not entirely clear, for example
Do you want difference in date per day (a user can make multiple orders per day) or just between their earliest and latest orders
What do you mean by average is it just (latest order date - earliest order date) / total purchase? This will be hours / purchase. is it even useful?
Anyways, here is a working sheet, this will give enough to set you in right direction (hopefully). This is for Oracle database, will work mostly for other database except the time conversion functions used here. You will have to search and use equivalent functions for database of your choice, if its not Oracle.
Create table
create table tbl_order(
order_id integer,
user_id integer,
item varchar2(100),
ordered_at date
);
Insert some data
insert into tbl_order values (8, 1, 'A2Z', to_date('21-Mar-2019 16:30:20', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (1, 1, 'ABC', to_date('22-Mar-2019 07:30:20', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (2, 1, 'ABC', to_date('22-Mar-2019 07:30:20', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (3, 1, 'EFGT', to_date('22-Mar-2019 09:30:30', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (4, 1, 'XYZ', to_date('22-Mar-2019 12:38:50', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (5, 1, 'ABC', to_date('22-Mar-2019 16:30:20', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (6, 2, 'ABC', to_date('22-Mar-2019 14:20:20', 'DD-MON-YYYY HH24:MI:SS'));
insert into tbl_order values (7, 2, 'A2C', to_date('22-Mar-2019 14:20:50', 'DD-MON-YYYY HH24:MI:SS'));
Get latest, earliest and total_purchase per user and an average
WITH VW AS (
SELECT USER_ID,
TO_CHAR(MIN(ORDERED_AT), 'DD-MON-YYYY HH24:MI:SS') EARLIEST_ORDER_AT,
TO_CHAR(MAX(ORDERED_AT), 'DD-MON-YYYY HH24:MI:SS')LATEST_ORDER_AT,
ROUND(MAX(ORDERED_AT) - MIN(ORDERED_AT), 5) * 24 DIFF_IN_HOURS,
COUNT(*) TOTAL_ORDER_COUNT
FROM TBL_ORDER
GROUP BY USER_ID
)
SELECT USER_ID, EARLIEST_ORDER_AT, LATEST_ORDER_AT,
DIFF_IN_HOURS, DIFF_IN_HOURS/TOTAL_ORDER_COUNT AVERAGE
FROM VW;
Get latest, earliest and total_purchase per user per day and an average
WITH VW AS (
SELECT USER_ID, TO_CHAR(ORDERED_AT, 'DD-MON-YYYY') ORDER_DATE_PART,
TO_CHAR(MIN(ORDERED_AT), 'DD-MON-YYYY HH24:MI:SS') EARLIEST_ORDER_AT,
TO_CHAR(MAX(ORDERED_AT), 'DD-MON-YYYY HH24:MI:SS')LATEST_ORDER_AT,
ROUND(MAX(ORDERED_AT) - MIN(ORDERED_AT), 5) * 24 DIFF_IN_HOURS,
COUNT(*) TOTAL_ORDER_COUNT
FROM TBL_ORDER
GROUP BY USER_ID, TO_CHAR(ORDERED_AT, 'DD-MON-YYYY')
)
SELECT USER_ID, ORDER_DATE_PART, EARLIEST_ORDER_AT, LATEST_ORDER_AT,
DIFF_IN_HOURS, DIFF_IN_HOURS/TOTAL_ORDER_COUNT AVERAGE
FROM VW;

SQL Server 2014 - Use previous value when date not present

I asked a similar question yesterday but I was not very good in my description of what I wanted. This will be far clearer.
Lead/Lag is not getting me what I need. Its close, but not enough.
Using SQL Server 2014 for client, actual server built on SQL 2012.
Here is my code:
Creating Team Table
CREATE TABLE ##TeamTable
([UserID] varchar(50), [CurrentTeam] varchar(5), [ChangeDate] datetime)
;
INSERT INTO ##TeamTable
([UserID], [CurrentTeam], [ChangeDate])
VALUES
('User1', 'Team1', '6/1/2016'),
('User1', 'Team2', '9/1/2016'),
('User1', 'Team3', '12/1/2016'),
('User2', 'Team1', '4/1/2016'),
('User2', 'Team2', '10/1/2016'),
('User2', 'Team3', '11/1/2016');
Now to create data table I need to join to
CREATE TABLE ##DataTable
([UserID] varchar(50), Month_sk datetime, Media varchar(50), NCO int)
INSERT INTO ##DataTable
([UserID] , Month_sk , Media , NCO )
VALUES
('User1', '2016-06-01 00:00:00', 'Fax', 100),
('User1', '2016-06-01 00:00:00', 'Voice', 120),
('User1', '2016-07-01 00:00:00', 'Voice', 90),
('User1', '2016-07-01 00:00:00', 'Email', 100),
('User1', '2016-08-01 00:00:00', 'Voice', 150),
('User1', '2016-08-01 00:00:00', 'Email', 100),
('User1', '2016-09-01 00:00:00', 'Voice', 100),
('User1', '2016-09-01 00:00:00', 'Email', 120),
('User1', '2016-10-01 00:00:00', 'Voice', 90),
('User1', '2016-10-01 00:00:00', 'Email', 100),
('User1', '2016-11-01 00:00:00', 'Voice', 150),
('User1', '2016-11-01 00:00:00', 'Email', 100),
('User1', '2016-12-01 00:00:00', 'Voice', 150),
('User1', '2016-12-01 00:00:00', 'Email', 100),
('User2', '2016-04-01 00:00:00', 'Fax', 100),
('User2', '2016-04-01 00:00:00', 'Voice', 120),
('User2', '2016-05-01 00:00:00', 'Fax', 100),
('User2', '2016-05-01 00:00:00', 'Voice', 120),
('User2', '2016-06-01 00:00:00', 'Fax', 100),
('User2', '2016-06-01 00:00:00', 'Voice', 120),
('User2', '2016-07-01 00:00:00', 'Voice', 90),
('User2', '2016-07-01 00:00:00', 'Email', 100),
('User2', '2016-08-01 00:00:00', 'Voice', 150),
('User2', '2016-08-01 00:00:00', 'Email', 100),
('User2', '2016-09-01 00:00:00', 'Voice', 100),
('User2', '2016-09-01 00:00:00', 'Email', 120),
('User2', '2016-10-01 00:00:00', 'Voice', 90),
('User2', '2016-10-01 00:00:00', 'Email', 100),
('User2', '2016-11-01 00:00:00', 'Voice', 150),
('User2', '2016-11-01 00:00:00', 'Email', 100),
('User2', '2016-12-01 00:00:00', 'Voice', 150),
('User2', '2016-12-01 00:00:00', 'Email', 100);
Here is a basic Select to show whats going on:
SELECT b.UserID
,b.Media
,b.NCO
,Month_sk
,CurrentTeam
FROM ##DataTable b
LEFT OUTER JOIN ##TeamTable a on b.UserID = a.UserID and b.Month_sk = a.ChangeDate
order by UserID, Month_sk, media
This gives me a result set that looks like this:
What I need is for where I have nulls, that it would be pulling in the previous team name that's not null. So in User1 case, those 4 nulls for months of July and August would say Team1 since that was the team he was last on. Same for the nulls after Team2, those should say Team2.
Lead/Lag is close or I'm not using it right. Hopefully with all this code, this makes someone's jobs way easier.
UPDATE:
Lag/Lead gives same results. Still need the nulls to fill in
SELECT b.UserID
,b.Media
,b.NCO
,Month_sk
,CurrentTeam
,LAG(CurrentTeam,1, currentteam) OVER(PARTITION BY a.userid, changedate ORDER BY ChangeDate) as Lag
FROM ##DataTable b
LEFT OUTER JOIN ##TeamTable a on b.UserID = a.UserID and b.Month_sk = a.ChangeDate
order by UserID, Month_sk, media
(Moving update notes to end)
I think the easiest solution (conceptually) is to join against all months up to month_sk and then filter to get only the last match. This "feels" potentially inefficient, so you'd want to test it with realistic data volume and if there's a problem then look for something better. (But "something better" may involve changes to the physical data model...)
So:
select userid, media, nco, month_sk, currentteam
from (SELECT b.UserID
, b.Media
, b.NCO
, Month_sk
, CurrentTeam
, rank() over(partition by b.userID
order by a.changeDate desc) n
FROM ##DataTable b
INNER JOIN ##TeamTable a
on b.UserID = a.UserID
and b.Month_sk >= a.ChangeDate
) x
where n = 1
order by UserID, Month_sk, media
Note that in previous versions I used row_number() over() instead of rank() over()... and you can do that, but if you do then you have to include in the partitioning key any data from the b table that could cause a duplication of a row from the a table during the join. Using rank ensures that all such duplicates share their rank as they ought to.
UPDATE - After I initially wrote this, I deleted it because I thought I'd misread your question; but as I was writing a replacement realized I may have had it right in the first place. So here it is, with a caveat:
This assumes that the only reason you get the NULL value is the outer join. If ever the "right hand" table has a row and just a value for a column therein is NULL, then getting the previous value for that column would require further work with subqueries or analytic funcitons. But even then lead/lag may not work, since they are position based. (I think something with LAST_VALUE might be more suitable, but will leave the details of that unless it's needed.)
UPDATE 2 - based on your description of the data model in below comments, I'm changing the query to show an inner join as it sounds like that will work (once you broaden the join criteria) and should be more efficient.
UPDATE 3 - I did misread your sample data and got the partitioning expression for calculating n wrong. Should be fixed assuming the values from the b table are unique. If not it's still fixable but requires more trickery...
You can do this with an APPLY and a sub query like this.
SELECT
userid,
media,
nco,
month_sk,
currentteam
FROM
##DataTable td
OUTER APPLY (
SELECT TOP (1)
CurrentTeam,
ChangeDate
FROM
##TeamTable tt
WHERE
tt.UserID = td.UserID
and tt.ChangeDate <= td.Month_sk
ORDER BY
tt.ChangeDate desc
) dataTableWithTeam
ORDER BY
td.UserID,
td.Month_sk,
td.media
In this version, I first identify the appropriate "linking" month in the CTE, and then use that as a lookup in the final join. (It got much easier once I realized Media and NCO played no real part in the join.)
WITH cteDateLookup
as (
-- Get the ChangeDate for this User/Month
SELECT
b.UserID
,b.Month_sk
,max(a.ChangeDate) ChangeDate
from ##DataTable b
left outer join ##TeamTable a
on b.UserID = a.UserID
and b.Month_sk >= a.ChangeDate
group by
b.UserID
,b.Month_sk
)
-- Use the cte as a "lookup" for the appropriate date
SELECT
b.UserID
,b.Media
,b.NCO
,b.Month_sk
,a.CurrentTeam
from ##DataTable b
left outer join cteDateLookup cte
on cte.UserId = b.UserId
and b.Month_sk = cte.Month_sk
left outer join ##TeamTable a
on a.UserId = cte.UserId
and a.ChangeDate = cte.ChangeDate
order by
b.UserID
,b.Month_sk
,b.media

sum before joining two table

CREATE TABLE Daily
([DATE] datetime, [sales] int)
;
INSERT INTO Daily
([DATE], [sales])
VALUES
('2012-01-01 00:00:00', 1),
('2012-01-02 00:00:00', 2),
('2012-01-03 00:00:00', 3),
('2012-01-04 00:00:00', 4),
('2012-01-05 00:00:00', 5),
('2012-01-06 00:00:00', 6),
('2012-01-06 00:00:00', 5),
('2012-01-07 00:00:00', 7),
('2012-01-08 00:00:00', 8),
('2012-01-09 00:00:00', 9),
('2012-01-10 00:00:00', 10),
('2012-01-11 00:00:00', 11),
('2012-01-12 00:00:00', 12),
('2012-01-13 00:00:00', 13),
('2012-01-14 00:00:00', 14),
('2012-01-15 00:00:00', 15),
('2012-01-16 00:00:00', 16)
;
CREATE TABLE Weekly
([Weekly] datetime)
;
INSERT INTO Weekly
([Weekly])
VALUES
('2012-01-07 00:00:00'),
('2012-01-14 00:00:00'),
('2012-01-21 00:00:00')
;
i want the final output
Sales
1/7/2012 33
1/14/2012 77
any help on this would be appreciated. thanks in advance
I would strongly reccommend against storing this in a table, if any of your daily data changes your weekly data will need to be changed to or it will be wrong, instead create a view as follows:
CREATE VIEW Weekly
AS
SELECT WeekEnd = DATEADD(WEEK, DATEDIFF(WEEK, 0, [DATE]) + 1, -2),
Sales = SUM(Sales)
FROM Daily
GROUP BY DATEADD(WEEK, DATEDIFF(WEEK, 0, [DATE]) + 1, -2);
You can use this in the same way you would the table you want create, but this will always be in sync with the daily data. If you want to change your week start/end day (i.e. monday-sunday) you can change the -2 in the DATEADD function to alter this.
Example on SQL Fiddle
(Based on the [] around column names I am guessing this is SQL-Server.)