Join on Multiple columns with duplicates - sql-server

I have two tables Master table and the Matched Master Table based on the same saldate , saltime , lctid ,masid the counts has to be pulled up
For count(masid,saldate,saltime,lctid)>1 , for masid 121 in master table there are 5 records in Master Matched 3 records, I need to get the output which are not in Mactched and how much in Master and the total amount with the masid
Master
ID Saldate SalTime lctid masid Sal_amt
101 1/1/2000 100 120 121 15
102 1/1/2000 100 120 121 25
103 1/1/2000 100 120 121 100
118 1/1/2001 120 118 201 25
119 1/1/2009 302 222 187 60
104 1/1/2000 100 120 121 125
108 1/1/2000 100 120 121 22
Master matched
ID Saldate SalTime lctid masid Sal_Amt
101 1/1/2000 100 120 121 15
102 1/1/2000 100 120 121 25
118 1/1/2001 120 118 201 25
119 1/1/2009 302 222 187 60
OP1-Master OP2-Master matched
Masid Count(iD) SalAMt Masid Count(iD) Sal_Amt
121 3 247 121 2 40

Related

Running (Average True Range) calculation in a column SQL

I have a dataset of price data and would like to get the calculation of the ongoing ATR (Average True Range) for all rows > 21. Row 21 is the AVG([TR]) from Rows 2-21 and is equal to 353.7.
The calculation that needs to be continuous for the rest of that [ATR_20] column will need to be:
ATR_20 (after row 21) = (([Previous ATR_20]*19)+[TR])/20
My dataset:
Date Open High Low Close TotalVolume Prev_Close TR_A TR_B TR_C TR ATR
2017-02-01 5961 5961 5425 5498 22689 NULL 536 NULL NULL NULL NULL
2017-02-02 5697 5868 5615 5734 22210 5498 253 370 117 370 NULL
2017-02-03 5742 5811 5560 5725 15852 5734 251 77 174 251 NULL
2017-02-06 5675 5679 5545 5554 9777 5725 134 46 180 180 NULL
2017-02-07 5597 5613 5426 5481 12692 5554 187 59 128 187 NULL
2017-02-08 5459 5630 5450 5625 9134 5481 180 149 31 180 NULL
2017-02-09 5615 5738 5532 5668 10630 5625 206 113 93 206 NULL
2017-02-10 5651 5661 5488 5602 9709 5668 173 7 180 180 NULL
2017-02-13 5700 6195 5639 6161 26031 5602 556 593 37 593 NULL
2017-02-14 6197 6594 6073 6571 35969 6161 521 433 88 521 NULL
2017-02-15 6510 6650 6275 6492 22046 6571 375 79 296 375 NULL
2017-02-16 6505 6680 6325 6419 12515 6492 355 188 167 355 NULL
2017-02-17 6434 6670 6429 6658 14947 6419 241 251 10 251 NULL
2017-02-21 6800 6957 6603 6654 23838 6658 354 299 55 354 NULL
2017-02-22 6704 6738 6145 6222 25004 6654 593 84 509 593 NULL
2017-02-23 6398 6437 5901 6343 46677 6222 536 215 321 536 NULL
2017-02-24 5280 5589 5260 5404 51757 6343 329 754 1083 1083 NULL
2017-02-27 5437 5461 5260 5300 19831 5404 201 57 144 201 NULL
2017-02-28 5258 5410 5167 5195 15900 5300 243 110 133 243 NULL
2017-03-01 5251 5299 5052 5215 16958 5195 247 104 143 247 NULL
2017-03-02 5160 5231 5063 5130 17805 5215 168 16 152 168 353.7
2017-03-03 5141 5363 5088 5320 14516 5130 275 233 42 275 NULL
I got to this point by the following
WITH cte_ACIA ([RowNumber], [Date], [Open], [High], [Low], [Close],
[Prev_Close], [TotalVolume], [TR_A], [TR_B], [TR_C])
AS
(SELECT
ROW_NUMBER() OVER (ORDER BY [Date] ASC) RowNumber,
[Date],
[Open],
[High],
[Low],
[Close],
LAG([Close]) OVER(ORDER BY [Date]) AS Prev_Close,
[TotalVolume],
ROUND([High]-[Low], 5) AS TR_A,
ABS(ROUND([High]-LAG([Close]) OVER(ORDER BY [Date]), 5)) AS TR_B,
ABS(ROUND([Low]-LAG([Close]) OVER(ORDER BY [Date]), 5)) AS TR_C,
FROM NASDAQ.ACIA_TEMP)
SELECT [RowNumber], [Date], [Open], [High], [Low], [Close], [Prev_Close],
[TotalVolume], [TR_A], [TR_B], [TR_C], [TR],
CASE
WHEN RowNumber = 21 THEN AVG([TR]) OVER (ORDER BY [Date] ASC ROWS 19 PRECEDING)
END AS ATR_20
FROM
(
SELECT [RowNumber],[Date],[Open],[High],[Low],[Close],
IIF(RowNumber = 1, NULL, Prev_Close) Prev_Close,
[TotalVolume],
[TR_A],
IIF(RowNumber > 1, [TR_B], NULL) TR_B,
IIF(RowNumber > 1, [TR_C], NULL) TR_C,
CASE
WHEN TR_A > TR_B AND TR_A > TR_C THEN TR_A
WHEN TR_B > TR_A AND TR_B > TR_C THEN TR_B
ELSE TR_C
END AS TR
FROM cte_ACIA) sub
Please let me know if you have questions or I need to clarify anything.
I suppose you are just looking for a hint. Otherwise you would have posted your table definition. We can't construct a query for you since we don't have the basic pieces. However, here's the hint! Use an aggregating window function with the OVER clause specifying ROWS PRECEDING.
See SELECT - OVER Clause

How can I get the differences between the OrderStop date and the OrderStart date in the next column?

How can I get the differences between the OrderStop and the OrderStart in the next column?
For example, row 1 has OrderStop date of 1/31/2007 I want to count the days between the next start date 1/26/2007 I know they are overlaps.
ID OrderStart OrderStop
132 4/14/2006 1/31/2007
132 1/26/2007 3/14/2007
132 2/1/2007 3/2/2007
132 3/2/2007 3/14/2007
132 3/14/2007 1/8/2010
132 11/26/2008 1/20/2011
132 1/8/2010 7/14/2010
132 7/14/2010 8/15/2012
132 8/15/2012 1/17/2013
132 1/17/2013 3/22/2013
132 3/21/2013 5/2/2013
132 5/2/2013 8/2/2013
132 5/22/2013 8/2/2013
132 7/29/2013 3/6/2014
132 3/5/2014 7/16/2014
132 7/16/2014 6/19/2015
132 8/21/2014 6/19/2015
132 6/19/2015 4/1/2016
132 6/25/2015 9/9/2015
132 4/1/2016 5/3/2016
132 5/3/2016 7/27/2016
132 8/15/2016 11/2/2016
I am trying to accomplished the below. How can I create a SQL statement that can accomplish this?
132 4/14/2006 1/31/2007
132 1/26/2007 4/1/2016
132 4/1/2016 7/27/2016
132 8/15/2016 11/2/2016
Consumable sample data makes things much easier for us. So does the version of SQL server. Below is a solution that uses 2012's LEAD functionality. The second one is for pre-2012 systems; it accomplishes the same thing but requires a self join and will not be as efficient.
declare #orders table (id int, orderStart date, orderStop date);
insert #orders
values
(132,'4/14/2006 ','1/31/2007'),
(132,'1/26/2007 ','3/14/2007'),
(132,'2/1/2007 ','3/2/2007 '),
(132,'3/2/2007 ','3/14/2007'),
(132,'3/14/2007 ','1/8/2010 '),
(132,'11/26/2008','1/20/2011'),
(132,'1/8/2010 ','7/14/2010'),
(132,'7/14/2010 ','8/15/2012'),
(132,'8/15/2012 ','1/17/2013'),
(132,'1/17/2013 ','3/22/2013'),
(132,'3/21/2013 ','5/2/2013 '),
(132,'5/2/2013 ','8/2/2013 '),
(132,'5/22/2013 ','8/2/2013 '),
(132,'7/29/2013 ','3/6/2014 '),
(132,'3/5/2014 ','7/16/2014'),
(132,'7/16/2014 ','6/19/2015'),
(132,'8/21/2014 ','6/19/2015'),
(132,'6/19/2015 ','4/1/2016 '),
(132,'6/25/2015 ','9/9/2015 '),
(132,'4/1/2016 ','5/3/2016 '),
(132,'5/3/2016 ','7/27/2016'),
(132,'8/15/2016 ','11/2/2016');
select *,
nextStart = lead(orderStart,1) over (order by orderStart),
daysBetween = abs(datediff(day,lead(orderStart,1) over (order by orderStart), orderStop))
from #orders
order by orderStart;
with preSort as
(
select *, rn = row_number() over (order by orderstart)
from #orders
)
select p2.id, p2.orderStart, p2.orderStop , nextStart = p1.orderStart,
daysBetween = abs(datediff(day, p2.orderStop, p1.orderStart))
from preSort p1 join preSort p2 on p1.rn = p2.rn+1
order by p1.orderStart;
Both Return
id orderStart orderStop nextStart daysBetween
----------- ---------- ---------- ---------- -----------
132 2006-04-14 2007-01-31 2007-01-26 5
132 2007-01-26 2007-03-14 2007-02-01 41
132 2007-02-01 2007-03-02 2007-03-02 0
132 2007-03-02 2007-03-14 2007-03-14 0
132 2007-03-14 2010-01-08 2008-11-26 408
132 2008-11-26 2011-01-20 2010-01-08 377
132 2010-01-08 2010-07-14 2010-07-14 0
132 2010-07-14 2012-08-15 2012-08-15 0
132 2012-08-15 2013-01-17 2013-01-17 0
132 2013-01-17 2013-03-22 2013-03-21 1
132 2013-03-21 2013-05-02 2013-05-02 0
132 2013-05-02 2013-08-02 2013-05-22 72
132 2013-05-22 2013-08-02 2013-07-29 4
132 2013-07-29 2014-03-06 2014-03-05 1
132 2014-03-05 2014-07-16 2014-07-16 0
132 2014-07-16 2015-06-19 2014-08-21 302
132 2014-08-21 2015-06-19 2015-06-19 0
132 2015-06-19 2016-04-01 2015-06-25 281
132 2015-06-25 2015-09-09 2016-04-01 205
132 2016-04-01 2016-05-03 2016-05-03 0
132 2016-05-03 2016-07-27 2016-08-15 19
132 2016-08-15 2016-11-02 NULL NULL

How to bulk update the date column

I have a table with 10000 records.
Sample
Id Transaction_Id Contract_Id Contractor_Id ServiceDetail_Id ServiceMonth UnitsDelivered CreateDate
----------------------------------------------------------------------------------------------------------------------------
1 1 352 466 590 2016-03-01 203 2016-04-25 17:01:55.000
2 1 352 466 566 2016-03-01 200 2016-04-25 17:02:38.807
3 1 352 466 138 2016-04-13 20 2016-04-13 00:00:00.000
5 1 352 466 138 2016-04-14 21 2016-04-13 00:00:00.000
6 10011 40 460 68 2016-03-17 10 2016-04-25 17:20:13.413
7 10011 40 460 511 2016-03-17 15 2016-04-25 17:20:13.413
8 10011 40 460 1611 2016-03-17 20 2016-04-25 17:20:13.413
9 20011 352 466 2563 2016-02-05 10 2016-04-25 17:20:25.307
11 100 40 460 68 2016-03-17 10 2016-04-25 17:29:23.653
In this table I have servicemonth with different dates.
I want to update the servicemonth column to the existing months last date.
suppose if I have 2016-03-17 in the table, it should be updated to 2016-3-31
suppose if I have 2016-05-12 in the table, it should be updated to 2016-5-31
Can anyone suggest a single query to update this?
EOMONTH: Returns the last day of the month that contains the specified date, with an optional offset.
UPDATE ... SET servicemonth = EOMONTH(servicemonth)
Update servicemonth
set servicemonth = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
--replace getdate() with the date column for which you want the end day of the month

How to get the latest value per time interval in SQL Server

SELECT RIGHT(timestamp,LEN(timestamp) -12) as DailyTime, left(roundtrip, LEN(roundtrip) -2) as HalfHourDuration, site_code
FROM tblServer_Status
WHERE timestamp >= dateadd(day, datediff(day,'19000101',CURRENT_TIMESTAMP),'19000101') AND timestamp < dateadd(day, datediff(day,'19000101',CURRENT_TIMESTAMP)+1,'19000101') AND server = 'ServerName' AND site_code = 'A'
GROUP BY timestamp, roundtrip, site_code HAVING(((COUNT(site_code))>0))
ORDER BY timestamp
I have this code that gives me this kind of output
| DailyTime | HalfHourDuration | Site_Code|
12:00AM 122 A
12:00AM 143 A
12:00AM 242 A
12:30AM 112 A
12:30AM 222 A
12:30AM 462 A
01:00AM 322 A
01:00AM 642 A
01:00AM 322 A
01:30AM 146 A
01:30AM 167 A
01:30AM 116 A
02:00AM 163 A
02:00AM 145 A
02:00AM 121 A
02:30AM 149 A
02:30AM 135 A
02:30AM 111 A
...................................
But I need to get the Latest duration per time.
Like this one
| DailyTime | HalfHourDuration | Site_Code|
12:00AM 242 A
12:30AM 462 A
01:00AM 322 A
01:30AM 116 A
02:00AM 121 A
02:30AM 111 A
Something like that.
can anyone help me configure my codes.
Thanks.
You can do this using row_number():
with t as (
<your query here without order by>
)
select t.*
from (select t.*,
row_number() over (partition by DailyTime
order by HalfHourDuration desc
) as seqnum
from t
) t
where seqnum = 1;
Add Max function to your column HalfHourDuration.
This will list out the maximum value of the roundtrip alone grouping by timestamp

Average value depending on cumulative value from other column aka running total

I've sifted through the various sql-server tagged threads using AVERAGE and Cumulative as search terms. Various desperate answers, but I can't cobble them together for my needs. The use case is to find the initial average value (cumulative value/cumulative days on) for a time period when cumulative days on is greater than 60 and less than 90.
Below is a table where ID identifies the object, VALUE is the amount reported on a monthly basis and DAYSON is the number of days in that month where the object ran to produce the value. YEARMONTH is date value on which on can sort.
ID VALUE DASYON YEARMONTH
1 166 27 201502
1 1 2 201505
1 569 19 201507
1 312 19 201508
2 364 27 201502
2 328 31 201503
2 242 29 201504
2 273 31 201505
2 174 30 201506
2 188 25 201507
2 203 25 201508
3 474 28 201502
3 521 31 201503
3 465 30 201504
3 473 31 201505
3 434 30 201506
3 404 31 201507
I would like to create a summary table that averages the cumulative value divided by the cumulative days uniquely for each ID where cumulative days is greater than 60 and less than 90. Below is a table that with the cumulative values. (I generated this in Excel)
ID VALUE cumValue DASYON cumDaysOn YEARMONTH
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
I try this based on other threads:
SELECT
ID,
Value,
SUM(Value) OVER (ORDER BY ID, YearMonth) [cumValue],
DaysOn,
SUM (DaysOn) OVER (Order by ID, YearMonth) as cumDaysOn,
YearMonth
FROM table
WHERE DAYSON > 0 and Liquid > 0 and YearMonth > 201501
GROUP BY ID, YearMonth, Value, DaysOn
ORDER BY ID, yearmonth
I can't get it to iterate over the ID; it just keeps summing down the column. If I could create a table or view like the one above, then I could always use a select statement and divide cumvalue by cumdayson.
Below is a table to show where I would get the initial average value (InititalAverageValue) based on the criteria:
ID VALUE cumValue DASYON cumDaysOn YEARMONTH InitalAvgValue
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508 55
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504 32
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504 18
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
Ultimately what I desire is table as such:
ID InitalAvgValue
1 55
2 32
3 18
Thanks in advance for any help.
The crux is that you need a running total. There are several approaches to calculating running totals, but they have various tradeoffs between simplicity and performance. The "best" approach depends on the expected size of your data set and whether you are using SQL Server 2012 or an earlier version. The following article describes some different options along with the pros and cons:
http://sqlperformance.com/2012/07/t-sql-queries/running-totals
Here's a quick example using correlated subqueries, which may be reasonable for small data sets, but likely would not scale well to larger data:
SELECT
ID,
ROUND(AVG(CAST(CumulativeValue AS FLOAT) / CAST(CumulativeDaysOn AS FLOAT)), 1) AS Average
FROM
(
SELECT
ID,
Value,
DaysOn,
(SELECT SUM(Value) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeValue,
(SELECT SUM(DaysOn) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeDaysOn
FROM
ExampleTable t1
) AS ExampleWithTotals
WHERE
CumulativeDaysOn > 60 AND CumulativeDaysOn < 90
GROUP BY
ID
ORDER BY
ID
;
Output:
ID Average
1 15.6
2 10.7
3 16.4

Resources