LEFT outer join returns returns duplicate rows even after adding distinct - sql

Restricting the price change table to select a particular item
select * from price
where item = '13'
results of the query above
item Date_Changed New Old START_DATE end_DATE
13 01/11/2018 00:00 5.61 4.88 01/11/2018 00:00 30/11/2018 00:00
13 30/11/2018 00:00 2.84 5.61 01/11/2018 00:00 17/12/2018 00:00
13 17/12/2018 00:00 2.39 2.84 30/11/2018 00:00 17/12/2018 00:00
sales table
Date Item Qty Amount
05/07/2018 00:00 13 3 14.64
05/07/2018 00:00 13 3 14.64
04/07/2018 00:00 13 3 14.64
02/07/2018 00:00 13 1 4.88
02/07/2018 00:00 13 6 29.28
06/07/2018 00:00 13 7 34.16
03/07/2018 00:00 13 4 19.52
12/07/2018 00:00 13 2 9.76
10/08/2018 00:00 13 1 4.88
Sample code
SELECT distinct a.[Inv]
, (CASE
WHEN a.Date <= b.START_DATE THEN (b.Old * a.Qty)
WHEN a.Date between b.START_DATE and b.dt_end_DATE THEN (b.New * a.Qty)
ELSE 0
END) as calc_amount
,(a.[amount] - (CASE
WHEN a.Date <= b.START_DATE THEN (b.Old * a.Qty)
WHEN a.Date between b.START_DATE and b.end_DATE THEN (b.New * a.Qty)
ELSE 0
END)) as variance
[sales] a
left outer join price b
on a.[Item] = b.item
where b.item = '13'
The script then returns 27 rows instead of 9 rows. can someone assist on how i can improve my script to be more accurate

Use outer apply. I assume you want the most recent start date from price, so this looks like:
select s.*,
(case when s.date <= p.start_date
then p.Old * s.Qty
else p.New * s.Qty
end) as calc_amount
from sales s outer apply
(select top (1) p.*
from prices p
where p.item = s.item and
p.start_date <= s.date
order by p.date desc
) p

I am not sure if this is what you are looking for. but perhaps you can skip the join?
I created 2 sample data with the columns that you might need.
DECLARE #price table (item varchar(2),date_start date, new_price numeric(9,2))
Insert into #price (item , date_start,new_price)
values
( '13', '20190101', '1.00'),
( '13', '20190102', '1.01'),
( '13', '20190103', '1.02')
DECLARE #sales table (item varchar(2),date_sales date,qty int)
Insert into #sales (item , date_sales,qty)
values
( '13', '20190101', '5'),
( '13', '20190101', '2'),
( '13', '20190102', '5'),
( '13', '20190102', '2'),
( '13', '20190103', '5'),
( '13', '20190103', '2')
declare #item as varchar(2) = '13'
SELECT (select top (1) new_price from #price b where a.date_sales>=b.date_start and b.item = #item order by b.date_start desc ) * a.qty as 'new_price* qty'
from #sales a
where a.item = #item
I have not tested this in a table with a huge data set, so I also can't vouch for the speed of this query. I believe it would be better to have some kind of other ID to join the table

Your question is not clear... You added sample data, but I doubt this is correct...
Your price table is open to erronous data. It would be better to store just the price and a validFrom-date. In this case you can pick the price on a give date easily. Your format is open to overlapping periodes and there is no good reason to store the former price once again. That's why I ignore all fields you should not use...
Try this. I've changed the dates in a way to simulate validity periodes.
A mock-up scenario (please to this the next time for us):
CREATE TABLE priceMock(item INT, Date_Changed DATE, New DECIMAL(10,4), Old DECIMAL(10,4), [START_DATE] DATE, end_DATE DATE);
SET DATEFORMAT dmy;
INSERT INTO priceMock VALUES
(13,'01/11/2018 00:00',5.61,4.88,'01/07/2018 00:00','06/07/2018 00:00')
,(13,'30/11/2018 00:00',2.84,5.61,'07/07/2018 00:00','10/07/2018 00:00')
,(13,'17/12/2018 00:00',2.39,2.84,'11/07/2018 00:00','15/08/2018 00:00');
GO
CREATE TABLE salesMock ([Date] DATE, Item INT, Qty INT, Amount DECIMAL(10,4));
SET DATEFORMAT dmy;
INSERT INTO salesMock VALUES
('05/07/2018 00:00',13,3,14.64)
,('05/07/2018 00:00',13,3,14.64)
,('04/07/2018 00:00',13,3,14.64)
,('02/07/2018 00:00',13,1,4.88 )
,('02/07/2018 00:00',13,6,29.28)
,('06/07/2018 00:00',13,7,34.16)
,('03/07/2018 00:00',13,4,19.52)
,('10/07/2018 00:00',13,2,9.76 )
,('10/08/2018 00:00',13,1,4.88 );
GO
I'd add an inline-table-valued-function to get exactly one single line back.
CREATE FUNCTION dbo.GetPriceForItemOnDate(#item INT,#ValidOn DATE)
RETURNS TABLE
AS
RETURN
SELECT TOP 1 *
FROM priceMock
WHERE item=#item
AND [START_DATE] <= #ValidOn
ORDER BY [START_DATE] DESC
GO
--This query will combine your sales data with the price valid on the given date
SELECT s.[Date]
,s.Item
,s.Qty
,p.New AS CurrentPrice
,s.Qty * p.New AS ComputedAmount
FROM salesMock s
OUTER APPLY dbo.GetPriceForItemOnDate(s.item,s.[Date]) p
GO
--Clean up (carefull with real data)
DROP FUNCTION dbo.GetPriceForItemOnDate;
DROP TABLE priceMock;
DROP TABLE salesMock;
The idea in short:
The function will first filter to price lines for the given item. The second filter will cut the list and return just the prices for the given date and before the given date. As we sort this by the date in descending order we will get the latest price on top. By using TOP 1 we return just the one single line we want.
General remark: I use a validFrom-approach here. But you can turn this to the opposite and use a validTo-approach. The idea is the same.

Related

Count records using Date filter related tables SQL Server

I'm trying to calculates the number of reports (report_user table) per user between two date (Calendar table) and by day worked (agenda_user table).
Here is the diagram of my tables:
Calendar table :
DATE Year Month
---------------------------------
2020-01-01 2020 1
2020-01-02 2020 1
2020-01-03 2020 1
2020-01-04 2020 1
AGENDA_USER table :
ID_USER DATE Value
---------------------------------
1 2020-01-01 1
2 2020-01-01 1
1 2020-01-02 0
2 2020-01-02 1
User table :
ID_USER Name
-------------------------
1 Jack
2 Robert
Report_Result table :
ID_USER Date Result
-----------------------------------
1 2020-01-01 good
1 2020-01-01 good
2 2020-01-01 bad
2 2020-01-01 good
2 2020-01-02 good
2 2020-01-02 good
Result I'm trying to find with an SQL query
ID_USER Date Number of report Day work report/work
---------------------------------------------------------------------------
1 2020-01-01 2 1 2/1 = 2
2 2020-01-01 2 1 1
1 2020-01-02 0 0 0
2 2020-01-02 2 1 2
SELECT
REPORT_USER.ID_USER,
COUNT(ID_USER) AS result
FROM [DB].[dbo].REPORT_USER AS report,
JOIN [DB].[dbo].[USER] AS [USER]
ON [USER].ID_USER = report.ID_USER
JOIN [DB].[dbo].AGENDA_USER AS agenda
ON agenda.ID_USER = report.ID_USER
WHERE CAST(agenda.[Date] AS DATE) >= '2020-09-01'
AND CAST(agenda.[Date] AS DATE) <= '2021-07-28'
AND [USER].ID_user = 1167
GROUP BY
report.ID_VENDEUR;
I'm not entirely sure I understand your problem, but I think I'm reasonably close so here is a start, point out my invalid assumptions and we can refine. More data, particularly in Agenda and Reports would really help. An explanation is below (plus see the comment in the code).
The overall flow is to generate a list of days/people you want to report on (cteUserDays), generate a list of how many reports each user generated on each date (cteReps), generate a list of who worked on what days (cteWork), and then JOIN all 3 parts together using a LEFT OUTER JOIN so the report covers all workers on all days.
EDIT: Add cteRepRaw where DATETIME is converted to DATE and "bad" reports are filtered out. Grouping and counting still happens in cteReps, but joining to cteUserDays is not there because it was adding 1 to count if there was a NULL.
DECLARE #Cal TABLE (CalDate DATETIME, CalYear int, CalMonth int)
DECLARE #Agenda TABLE (UserID int, CalDate DATE, AgendaVal int)
DECLARE #User TABLE (UserID int, UserName nvarchar(50))
DECLARE #Reps TABLE (UserID int, CalDate DATETIME, RepResult nvarchar(50))
INSERT INTO #Cal(CalDate, CalYear, CalMonth)
VALUES ('2020-01-01', 2020, 1), ('2020-01-02', 2020, 1), ('2020-01-03', 2020, 1), ('2020-01-04', 2020, 1)
INSERT INTO #Agenda(UserID, CalDate, AgendaVal)
VALUES (1, '2020-01-01', 1), (2, '2020-01-01', 1), (1, '2020-01-02', 0), (2, '2020-01-02', 1)
INSERT INTO #User (UserID , UserName )
VALUES (1, 'Jack'), (2, 'Robert')
INSERT INTO #Reps (UserID , CalDate , RepResult )
VALUES (1, '2020-01-01', 'good'), (1, '2020-01-01', 'good')
, (2, '2020-01-01', 'bad'), (2, '2020-01-01', 'good')
, (2, '2020-01-02', 'good'), (2, '2020-01-02', 'good')
; with cteUserDays as (
--First, you want zeros in your table where no reports are, so build a table for that
SELECT CONVERT(DATE, D.CalDate) as CalDate --EDIT add CONVERT here
, U.UserID FROM #Cal as D CROSS JOIN #User as U
WHERE D.CalDate >= '2020-01-01' AND D.CalDate <= '2021-07-28'
--EDIT Watch the <= date here, a DATE is < DATETIME with hours of the same day
), cteRepRaw as (--EDIT Add this CTE to convert DATETIME to DATE so we can group on it
--Map the DateTime to a DATE type so we can group reports from any time of day
SELECT R.UserID
, CONVERT(DATE, R.CalDate) as CalDate --EDIT add CONVERT here
, R.RepResult
FROM #Reps as R
WHERE R.RepResult='good' --EDIT Add this test to only count good ones
), cteReps as (
--Get the sum of all reports for a given user on a given day, though some might be missing (fill 0)
SELECT R.UserID , R.CalDate , COUNT(*) as Reports --SUM(COALESCE(R.RepResult, 0)) as Reports
FROM cteRepRaw as R--cteUserDays as D
--Some days may have no reports for that worker, so use a LEFT OUTER JOIN
--LEFT OUTER JOIN cteRepRaw as R on D.CalDate = R.CalDate AND D.UserID = R.UserID
GROUP BY R.UserID , R.CalDate
) , cteWork as (
--Unclear what values "value" in Agenda can take, but assuming it's some kind of work
-- unit, like "hours worked" or "shifts" so add them up
SELECT A.UserID , A.CalDate, SUM(A.AgendaVal) as DayWork FROM #Agenda as A
WHERE A.CalDate >= '2020-01-01' AND A.CalDate <= '2021-07-28'
GROUP BY A.CalDate, A.UserID
)
SELECT D.UserID , D.CalDate, COALESCE(R.Reports, 0) as Reports, W.DayWork
--NOTE: While it's probably a mistake to credit a report to a day a worker had
--no shifts, it could happen and would throw an error so check
, CASE WHEN W.DayWork > 0 THEN R.Reports / W.DayWork ELSE 0 END as RepPerWork
FROM cteUserDays as D
LEFT OUTER JOIN cteReps as R on D.CalDate=R.CalDate AND R.UserID = D.UserID
LEFT OUTER JOIN cteWork as W on D.UserID = W.UserID AND D.CalDate = W.CalDate
ORDER BY CalDate , UserID
First, as per the comments in your OP "Agenda" represents when the user is working, you don't say how it's structured so I'll assume it can have multiple entries for a given person on a given day (i.e. a 4 hour shift and an 8 hour shift) so I'll add them up to get total work (cteWork). I also assume that if somebody didn't work, you can't have a report for them. I check for this, but normally I'd expect your data validator to pre-screen those out.
Second, I'll assume reports are 1 per record, and a given user can have multiple per day. You have that in your given, but it's important to this solution so I'm restating in case somebody else reads this later.
Third, I assume you want all days reported for all users, I assure this by generating a CROSS join between users and days (cteUserDays)

SQL find average time difference between rows for a given category

I browsed SO but could not quite find the exact answer or maybe it was for a different language.
Let's say I have a table, where each row is a record of a trade:
trade_id customer trade_date
1 A 2013-05-01 00:00:00
2 B 2013-05-01 10:00:00
3 A 2013-05-02 00:00:00
4 A 2013-05-05 00:00:00
5 B 2013-05-06 12:00:00
I would like to have the average time between trades, in days or fraction of days, for each customer, and the number of days since last trade. So for instance for customer A, time between trades 1 and 3 is 1 day and between trades 3 and 4 is 3 days, for an average of 2. So the end table would look like something like this (assuming today it's the 2013-05-10):
customer avg_time_btw_trades time_since_last_trade
A 2.0 5.0
B 5.08 3.5
If a customer has only got 1 trade I guess NULL is fine as output.
Not even sure SQL is the best way to do this (I am working with SQL server), but any help is appreciated!
SELECT
customer,
DATEDIFF(second, MIN(trade_date), MAX(trade_date)) / (NULLIF(COUNT(*), 1) - 1) / 86400.0,
DATEDIFF(second, MAX(trade_date), GETDATE() ) / 86400.0
FROM
yourTable
GROUP BY
customer
http://sqlfiddle.com/#!6/eb46e/7
EDIT: Added final field that I didn't notice, apologies.
The following SQL script uses your data and gives the expected results.
DECLARE #temp TABLE
( trade_id INT,
customer CHAR(1),
trade_date DATETIME );
INSERT INTO #temp VALUES (1, 'A', '20130501');
INSERT INTO #temp VALUES (2, 'B', '20130501 10:00');
INSERT INTO #temp VALUES (3, 'A', '20130502');
INSERT INTO #temp VALUES (4, 'A', '20130505');
INSERT INTO #temp VALUES (5, 'B', '20130506 12:00');
DECLARE #getdate DATETIME
-- SET #getdate = getdate();
SET #getdate = '20130510';
SELECT s.customer
, AVG(s.days_btw_trades) AS avg_time_between_trades
, CAST(DATEDIFF(hour, MAX(s.trade_date), #getdate) AS float)
/ 24.0 AS time_since_last_trade
FROM (
SELECT CAST(DATEDIFF(HOUR, t2.trade_date, t.trade_date) AS float)
/ 24.0 AS days_btw_trades
, t.customer
, t.trade_date
FROM #temp t
LEFT JOIN #temp t2 ON t2.customer = t.customer
AND t2.trade_date = ( SELECT MAX(t3.trade_date)
FROM #temp t3
WHERE t3.customer = t.customer
AND t3.trade_date < t.trade_date)
) s
GROUP BY s.customer
You need a date difference between every trade and average them.
select
a.customer
,avg(datediff(a.trade_date, b.trade_date))
,datediff(now(),max(a.trade_date))
from yourTable a, yourTable b
where a.customer = b.customer
and b.trade_date = (
select max(trade_date)
from yourTable c
where c.customer = a.customer
and a.trade_date > c.trade_date)
#gets the one earlier date for every trade
group by a.customer
Just for grins I added a solution that would use CTE's. You could probably use a temp table if the first query is too large. I used #MatBailie creation script for the table:
CREATE TABLE customer_trades (
id INT IDENTITY(1,1),
customer_id INT,
trade_date DATETIME,
PRIMARY KEY (id),
INDEX ix_user_trades (customer_id, trade_date)
)
INSERT INTO
customer_trades (
customer_id,
trade_date
)
VALUES
(1, '2013-05-01 00:00:00'),
(2, '2013-05-01 10:00:00'),
(1, '2013-05-02 00:00:00'),
(1, '2013-05-05 00:00:00'),
(2, '2013-05-06 12:00:00')
;
;WITH CTE as(
select customer_id, trade_date, datediff(hour,trade_date,ISNULL(LEAD(trade_date,1) over (partition by customer_id order by trade_date),GETDATE())) Trade_diff
from customer_trades
)
, CTE2 as
(SELECT customer_id, trade_diff, LAST_VALUE(trade_diff) OVER(Partition by customer_id order by trade_date) Curr_Trade from CTE)
SELECT Customer_id, AVG(trade_diff) AV, Max(Curr_Trade) Curr_Trade
FROM CTE2
GROUP BY customer_id

SQL failing to add value from previous row into the next

I am trying to add the value of the previous row to the current row into the column cumulative
Select
Ddate as Date, etype, Reference, linkacc as ContraAcc,
Description,
sum(case when amount > 0 then amount else 0 end) as Debits,
sum(case when amount < 0 then amount else 0 end) as Credits,
sum(amount) as Cumulative
from
dbo.vw_LT
where
accnumber ='8400000'
and [DDate] between '2016-04-01 00:00:00' and '2016-04-30 00:00:00'
and [DataSource] = 'PAS11CEDCRE17'
group by
Ddate, etype, Reference, linkacc, Description, Amount
Output(what i am getting):
Date Reference ContraAcc Description Debits Credits Cumulative
--------------------------------------------------------------------------
2016-04-01 CC007 8000000 D/CC007 0 -39.19 -39.19
2016-04-01 CC007 8000000 D/CC007 1117.09 0 1117.09
2016-04-01 CC009 8000000 CC009 2600 0 2600
in the cumulative column should like below(what i need):
Date Reference ContraAcc Description Debits Credits Cumulative
--------------------------------------------------------------------------
2016-04-01 CC007 8000000 D/CC007 0 -39.19 -39.19
2016-04-01 CC007 8000000 D/CC007 1117.09 0 1077.9
2016-04-01 CC009 8000000 CC009 2600 0 3677.9
Before we delve into the solution, let me tell you that if you are using SQL Server version more than 2012, there are LAG and LEAD, which can help you to solve this.
I am not giving you an exact query to solve your problem (as we dont know what your primary key for that table is), but you can get the idea by seeing the below example
DECLARE #t TABLE
(
accountNumber VARCHAR(50)
,dt DATETIME
,TransactedAmt BIGINT
)
INSERT INTO #t VALUES ('0001','7/20/2016',1000)
INSERT INTO #t VALUES ('0001','7/21/2016',-1000)
INSERT INTO #t VALUES ('0001','7/22/2016',2000)
INSERT INTO #t VALUES ('0002','7/20/2016',500)
INSERT INTO #t VALUES ('0002','7/21/2016',-500)
INSERT INTO #t VALUES ('0002','7/22/2016',2000)
;WITH CTE AS
(
SELECT ROW_NUMBER() OVER(Partition by accountNumber order by dt) as RN, *
FROM #t
),CTE1 AS
(
SELECT *,TransactedAmt As TotalBalance
FROM CTE WHERE rn = 1
UNION
SELECT T1.*,T1.TransactedAmt + T0.TransactedAmt as TotalBalance
FROM CTE T1
JOIN CTE T0
ON T1.accountNumber = T0.accountNumber
AND T1.RN = T0.RN+1
AND T1.RN > 1
)
select * from CTE1 order by AccountNumber

How to group value within a certain date range or every certain days in SQL server

For example table would be:
Customer OrderDate OrderAmt
-------- ---------- ---------
A1 20140101 920.00
A2 20140111 301.00
A2 20140123 530.00
A1 20140109 800.00
A3 20140110 500.00
A1 20140115 783.00
A3 20140217 500.00
A1 20140219 1650.00
A1 20140225 780.00
...
A3 20140901 637.00
I want to group them and calculate the sum(OrderAmt) within every 20 days and group by customer start from 20140101.
For what it's worth, you can accomplish what you describe with a pretty simple DATEDIFF() / GROUP BY operation, as below: whether or not that is actually what you want might be another question. I suspect that the DateBucket calculation might actually be something else ...
CREATE TABLE #tmpCustomer (Customer VARCHAR(2), OrderDate VARCHAR(10), OrderAmt DECIMAL(6,2))
INSERT INTO #tmpCustomer (Customer, OrderDate, OrderAmt)
SELECT 'A1',20140101, 920.00 UNION
SELECT 'A2',20140111, 301.00 UNION
SELECT 'A2',20140123, 530.00 UNION
SELECT 'A1',20140109, 800.00 UNION
SELECT 'A3',20140110, 500.00 UNION
SELECT 'A1',20140115, 783.00 UNION
SELECT 'A3',20140217, 500.00 UNION
SELECT 'A1',20140219, 1650.00 UNION
SELECT 'A1',20140225, 780.00 UNION
SELECT 'A3',20140901, 637.00
SELECT
Customer,
(DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1 AS DateBucket,
SUM(OrderAmt) SumOrderAmt
FROM #tmpCustomer
GROUP BY Customer, (DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1
ORDER BY Customer, DateBucket
You need to do two things:
(1) Create some sort of guide hold the '20 day groups' information. A Recursive CTE does this pretty well, and
(2) Recast that varchar date as an actual date for comparison purposes.
Then it's just joining the order data into that daterange grouping and summing the order amounts.
-------------------------
-- Here i'm just recreating your example
-------------------------
DECLARE #customerOrder TABLE (Customer varchar(2), OrderDate varchar(8), OrderAmt decimal(8,2))
INSERT INTO #customerOrder (Customer, OrderDate, OrderAmt)
VALUES
('A1', '20140101', 920.00),
('A2', '20140111', 301.00),
('A2', '20140123', 530.00),
('A1', '20140109', 800.00),
('A3', '20140110', 500.00),
('A1', '20140115', 783.00),
('A3', '20140217', 500.00),
('A1', '20140219', 1650.00),
('A1', '20140225', 780.00),
('A3', '20140901', 637.00)
-------------------------
-- Set up a table that lists off 20 day periods starting from 1/1/2014
-------------------------
DECLARE #startDate datetime, #endDate datetime;
SET #startDate = {d N'2014-01-01'};
SET #endDate = {d N'2014-12-31'};
WITH [dates] ([Sequence], [startDate], [maxExcludedDate]) AS
(SELECT 1 AS [Sequence]
,#startDate AS [startDate]
,DATEADD(d, 20, #startDate) AS [maxExcludedDate]
UNION ALL
SELECT Sequence + 1 AS Sequence
,DATEADD(d, 20, [startDate]) AS [startDate]
,DATEADD(d, 40, [startDate]) AS [maxExcludedDate]
FROM [dates]
WHERE [startDate] < #endDate
)
, dateFrame AS
(
SELECT
[startDate]
,[maxExcludedDate]
FROM [dates]
)
-------------------------
-- Set up a table that holds the orderDates as actual dates
-------------------------
, castData AS
(
SELECT
cast(orderdate as datetime) castDate
,OrderAmt
FROM #customerOrder
)
-------------------------
-- JOIN and sum.
-------------------------
SELECT
[startDate]
, Sum(OrderAmt) perodAmt
FROM
dateFrame df
left join castData cd
on cd.castDate >= df.startDate
and cd.castDate < df.maxExcludedDate
GROUP BY
[startDate]
ORDER by
[startDate]
Assuming that the OrderDate is a numeric field (not varchar). I'm also assuming that you don't need to go much more than a year in the future. If you want the gaps shown, keep the left join, if you don't want the gaps, then make it an inner join. (You can also make the hardcoded date a variable of where to start, I just kept it as the 20140101 that you mentioned.
with Numbers as
(Select 0 as Num
UNION ALL
Select Num+1
FROM Numbers
WHERE Num+1<= 20
)
, DateList AS
(Select Year(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) * 10000+Month(DateAdd(dd,20*(Num), Cast('2014-01-01' as date)))*100+Day(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) Groupingdatemin
, Year(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*10000+ MONTH(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*100+DAY(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date))) Groupingdatemax
from Numbers
)
select Customer, sum(orderamt), Groupingdatemin, Groupingdatemax from DateLIst d LEFT JOIN
<yourtable> t on t.orderdate between d.Groupingdatemin and d.Groupingdatemax
group by customer, Groupingdatemin, Groupingdatemax

Selecting specific Data per month

So i have a table that would determine the Region Code of a Branch Depending on the Month,
Lets Say from January to february it's Region code would be 1, from February to March it would be 2 and for the month of april upto date would be 3
so here is the sample look of the table
i have a code that gets the data from a table, but what i want to achieve is that if the LoanDate of the selected Data is within the Dates above (between fld_Datefrom and fld_Dateto) it would use the fld_BranchRegion that is indicated like above above. (EG. the Loandate of the date is 2013-01-12 00:00:00 it would use the RegionCode 4A as indicated above and if the data is 2013-02-04 00:00:00 it would use the Region code 3
here is the code i use
SELECT
TE.LOAN
,bp.REGION
,BP.ID
,TE.AMOUNT
,te.ID
FROM #TrackExpired TE
inner join Transactions.TBLMAIN PM
on TE.ID = PM.ID
inner join #track BP
on BP.ID=cast(TE.ID/1000000000000 as decimal(38,0))
WHERE ((cast(TE.EXPIRATION as date) < cast(TE.newloandate as date))
OR(TE.NewLoanDate is null and (cast(TE.EXPIRATION as date) < cast(PM.REDEEMED as date))) or ((TE.NewLoanDate is null and PM.REDEEMED is null) and (PM.STATUS = 7 or PM.STATUS = 5)) )
The problem with this is that it generates duplicate values so i have 3 occurances of the dates in the #track table the number of the Data is also outputted 3 times with different Region Code!!
Instead of outputting them i would like to achive on selecting the Region Code from **#track
Based on the loan date of the Data.**
i just want to achieve that instead of outputting all of the region code, it would just use the Region code that is between the ranges based on the #track table provided..
Any Help? or other approach?? thank you!. sorry im new to SQL.
EDIT here is the code to create the temp tables.
#trackexpired
SELECT PH.ID
,PH.LOAN
,PH.EXPIRATION
,PH.AMOUNT
,(SELECT T3.LOAN FROM Transactions.HISTO T3 INNER JOIN
(
SELECT MIN(T2.ID) as pawnhisto
FROM Transactions.HISTO T2
WHERE T2.ID > PH.ID
AND PH.ID = T2.ID
) T4
ON T4.pawnhisto = T3.ID
)as 'NewLoanDate'
INTO #TrackExpired
FROM Transactions.HISTO PH
INNER JOIN Transactions.MAIN PM
ON PM.ID=PH.ID
WHERE YEAR(PH.LOAN) = #YEAR
#track
Select bt.CODE
,bp.ID
,AREA
,REGION
,NCODE
,FROM
,isnull(fld_Dateto,GETDATE()) as fld_Dateto
into #sort
from Transactions.tbl_BranchTracking bt
inner join Reference.tbl_BranchProfiles bp
on bt.CODE = bp.CODE
Select * into #track from #sort
where #YEAR >= year(FROM)
and
#YEAR <= year(fld_Dateto)
Test Data
create table #LoanTable (
ID int not null,
RegionCode nvarchar(50) not null,
LoanDate datetime not null
);
insert into #LoanTable values
(1,'5','10/01/2014'),
(2,'5','10/18/2014'),
(3,'5','10/02/2014'),
(4,'3','04/11/2014'),
(5,'3','04/05/2014'),
(6,'4A','01/09/2014'),
(7,'4A','01/05/2014')
create table #LoanDetailsTable (
ID int not null,
LoanAmount INT not null,
LoanDate datetime not null
);
insert into #LoanDetailsTable values
(1,5000,'10/15/2014'),
(2,1000,'10/11/2014'),
(3,2000,'10/09/2014'),
(4,1500,'04/13/2014'),
(5,5000,'04/17/2014'),
(6,500,'01/19/2014'),
(7,2500,'01/15/2014')
Query
;With RegCode
AS
(
SELECT RegionCode, MAX(MONTH(LoanDate)) [Month]
FROM #LoanTable
GROUP BY RegionCode
)
SELECT LDT.* , RC.RegionCode
FROM #LoanDetailsTable LDT INNER JOIN RegCode RC
ON MONTH(LDT.LoanDate) = RC.[Month]
Results
ID LoanAmount LoanDate RegionCode
1 5000 2014-10-15 00:00:00.000 5
2 1000 2014-10-11 00:00:00.000 5
3 2000 2014-10-09 00:00:00.000 5
4 1500 2014-04-13 00:00:00.000 3
5 5000 2014-04-17 00:00:00.000 3
6 500 2014-01-19 00:00:00.000 4A
7 2500 2014-01-15 00:00:00.000 4A
Using CTE extract the Month part of the date along with Region Code associated with it, then join it with you data table on Month of the loan date and extracted month in cte and get the Region code whatever it is at that time. happy days :)