SQL query - Difference between the values from two rows and two columns - sql

I am struggling to get this working, using T-SQL Query (SQL SERVER 2008) for the following problem:
Ky ProductID Start # End # Diff
1 100 10 12 0
2 100 14 20 2 (14 - 12)
3 100 21 25 1 (21 - 20)
4 100 30 33 5 (30 - 25)
1 110 6 16 0
2 110 20 21 4 (20 - 16)
3 110 22 38 1 (22 - 21)
as you can see I need the difference between values in two different rows and two columns.
I tried
with t1
( select ROW_NUMBER() OVER (PARTITION by ProductID ORDER BY ProductID, Start# ) as KY
, productid
, start#
, end#
from mytable)
and
select DATEDIFF(ss, T2.complete_dm, T1.start_dm)
, <Keeping it simple not including all the columns which I selected..>
FROM T1 as T2
RIGHT OUTER JOIN T1 on T2.Ky + 1 = T1.KY
and T1.ProductID = T2.ProductID
The problem with the above query is when the productID changes from 100 to 110 still it calculates the difference.
Any help in modifying the query or any simpler solution much appreciated.
Thanks

You can try below code for the required result :
select ky,Start,[End],(select [end] from table1 tt where (tt.ky)=(t.ky-1) and tt.ProductID=t.ProductID) [End_Prev_Row],
case ky when 1 then 0
else (t.start -(select [end] from table1 tt where (tt.ky)=(t.ky-1) and tt.ProductID=t.ProductID))
end as Diff
from table1 t
SQL FIDDLE

Try something like that. It should give you the difference you want. I'm getting the first row for each product in the first part and then recursively build up by using the next Ky.
with t1
as
(
select ProductID, Ky, 0 as Difference, [End#]
from mytable where ky = 1
union all
select m.ProductID, m.Ky, m.[Start#] - t1.[End#] as Difference, m.[End#]
from mytable m
inner join t1 on m.ProductID = t1.ProductID and m.Ky = t1.Ky + 1
)
select Ky, ProductID, Difference from t1
order by ProductID, Ky

As Anup has mentioned, your query seems to be working fine, I just removed DateDiff to calculate the difference, as I assume columns are not of DATE datatype from your example, I guess that was the issue, please find below the modified query
with t1
as
( select ROW_NUMBER() OVER (PARTITION by ProductID ORDER BY ProductID ) as KY
, productid
, st
, ed
from YourTable)
select T1.ProductID, t1.ST,t1.ED, ISNULL(T1.st - T2.ed,0) as Diff
FROM T1 as T2
RIGHT OUTER JOIN T1 on T2.KY+1 = T1.KY
and T1.ProductID = T2.ProductID

SELECT ROW_NUMBER() OVER (PARTITION by rc.ContractID ORDER BY rc.ID) AS ROWID,rc.ID,rc2.ID,rc.ContractID,rc2.ContractID,rc.ToDate,rc2.FromDate
FROM tbl_RenewContracts rc
LEFT OUTER JOIN tbl_RenewContracts rc2
ON rc2.ID = (SELECT MAX(ID) FROM tbl_RenewContracts rcs WHERE rcs.ID < rc.ID AND rcs.ContractID = rc.ContractID)
ORDER BY rc.ContractID
Replace your table name and columns and add calculated column to get the DATEDIFF.

Related

How can I use a Join from another table when im doing a Max to a column in ORACLE?

Getting This issue in which I'm using a Max to a Column, it returns me the number.
(My tables have already the Constraints).
Actual Return
CVEANO
CVENUMERO
CVEACCION
2021
7
4
2021
1
3
What I Want to Return from TblACCION
CVEANO
CVENUMERO
CVEACCION
CVEACCION NAME Brought from tblACCION
2021
7
4
NAME FOR NUMBER 4
2021
1
3
NAME FOR NUMBER 3
My actual Query is
SELECT
*
FROM
(
SELECT
cveano,
cvenumero,
max(cveaccion) as ultima
FROM
tblbitacoragf
WHERE
cveusuario = 1
GROUP BY
cvenumero,
cveano
order by max(fechaaccion) desc
)
WHERE ROWNUM <= 4
I've tried doing
INNER JOIN tblACCION ta USING (CVEACCION)
and in SELECT
ta.descripcion AS accion
but I guess there's something wrong, because it always asks me for
00000 - "missing right parenthesis"
and I did check for parenthesis, but there's no lack of parenthesis.
UPDATE
I've tried this 2.0 , nothing
As I understood, you are looking for something like this.
SELECT
*
FROM
(
SELECT
t1.cveano,
t1.cvenumero,
max(t1.cveaccion) as ultima,
max(t2.cveaccionName) as cveaccionName
FROM
tblbitacoragf t1
INNER JOIN tblACCION t2 ON t1.cveaccion = t2.cveaccion
WHERE
t1.cveusuario = 1
GROUP BY
t1.cvenumero,
t1.cveano
order by
max(t1.fechaaccion) desc
)
WHERE
ROWNUM <= 4
Also you can try this.
SELECT
abc.*,
xyz.cveaccionName
FROM
(
SELECT
cveano,
cvenumero,
max(cveaccion) as ultima
FROM
tblbitacoragf
WHERE
cveusuario = 1
GROUP BY
cvenumero,
cveano
order by
max(fechaaccion) desc
) abc
INNER JOIN tblACCION xyz ON abc.ultima = xyz.cveaccion
WHERE
ROWNUM <= 4

How to update every rows which has a number greater than or equal to the joining table?

Here is an example of the tables I am joining together (note: the tables have the exact same schema but are in different databases, I am trying to combine them):
Database 1 Table
UniqID UniqID2 Number
100 150 1
100 151 2
Database 2 Table
UniqID UniqID2 Number
100 152 2
100 153 3
I am trying to merge Table2 into Table1 and I'm joining on Table1.UniqID = Table2.UniqID. I don't want any overlapping values in the Number column, this is what I want the result to look like:
Table 1
UniqID UniqID2 Number
100 150 1
100 151 2
100 152 3
100 153 4
This is the query I have so far, but it only updates the row in Table 2 where the Number = 2 and doesn't increment the Number = 3 row. How can I adjust my query to do so?
UPDATE db2
Set db2.Number = db2.Number +
(SELECT MAX(Number) FROM [Database 1]..db1 WHERE UniqID = db2.UniqID)
FROM [Database 2]..table db2
INNER JOIN [Database 1]..Table db1
ON db1.UniqID = db2.UniqID
AND db1.Number = db2.Number
And this is what my Database 2 Table results look like right now:
Database 2 Table
UniqID UniqID2 Number
100 152 3
100 153 3
Basically, the only difference is that I want the Number = 3 to be Number = 4 in the second column.
I think you want a union all query and insert:
insert into table1(UniqID, UniqID2, Number)
select t2.UniqID, t2.UniqID2,
(x.maxn + row_number() over (order by (select null) ))
from table2 t2 cross join
(select max(number) as maxn from table1) x;
A different appraoch could be
UPDATE t2
SET t2.Number = t1.T1Number + 1
FROM table2 t2
INNER JOIN (SELECT uniqid, uniqid2, number as T1Number from Table1
union
SELECT uniqid, uniqid2, number as T1Number from Table2
) t1
ON t1.uniqid = t2.uniqid and t1.UniqID2 = t2.UniqID2-1
one more approach which works in SQL 2012..
Demo here
;With cte
as
(select *
from
#t
union all
select *
from #t1
)
select uniqid,uniqid2,
case when lag(number) over (order by uniqid,uniqid2) is null then number
when lead(number) over (order by uniqid,uniqid2) is null
then number+1 else lead(number) over (order by uniqid,uniqid2) end as nextnumber
from cte

How to SELECT top N rows that sum to a certain amount?

Suppose:
MyTable
--
Amount
1
2
3
4
5
MyTable only has one column, Amount, with 5 rows. They are not necessarily in increasing order.
How can I create a function, which takes a #SUM INT, and returns the TOP N rows that sum to this amount?
So for input 6, I want
Amount
1
2
3
Since 1 + 2 + 3 = 6. 2 + 4 / 1 + 5 won't work since I want TOP N ROWS
For 7/8/9/10, I want
Amount
1
2
3
4
I'm using MS SQL Server 2008 R2, if this matters.
Saying "top N rows" is indeed ambiguous when it comes to relational databases.
I assume that you want to order by "amount" ascending.
I would add a second column (to a table or view) like "sum_up_to_here", and create something like that:
create view mytable_view as
select
mt1.amount,
sum(mt2.amount) as sum_up_to_here
from
mytable mt1
left join mytable mt2 on (mt2.amount < mt1.amount)
group by mt1.amount
or:
create view mytable_view as
select
mt1.amount,
(select sum(amount) from mytable where amount < mt1.amount)
from mytable mt1
and then I would select the final rows:
select amount from mytable_view where sum_up_to_here < (some value)
If you don't bother about performance you may of course run it in one query:
select amount from
(
select
mt1.amount,
sum(mt2.amount) as sum_up_to_here
from
mytable mt1
left join mytable mt2 on (mt2.amount < mt1.amount)
group by mt1.amount
) t where sum_up_to_here < 20
One approach:
select t1.amount
from MyTable t1
left join MyTable t2 on t1.amount > t2.amount
group by t1.amount
having coalesce(sum(t2.amount),0) < 7
SQLFiddle here.
In Sql Server you can use CDEs to make it pretty simple to read.
Here is a CDE I did to sum up totals used in sequence. The CDE is similar to the joins above, and holds the total up to any given index. Outside of the CDE I join it back to the original table so I can select it along with other fields.
;with summrp as (
select m1.idx, sum(m2.QtyReq) as sumUsed
from #mrpe m1
join #mrpe m2 on m2.idx <= m1.idx
group by m1.idx
)
select RefNum, RefLineSuf, QtyReq, ProjectedDate, sumUsed from #mrpe m
join summrp on summrp.idx=m.idx
In SQL Server 2012 you can use this shortcut to get a result like Grzegorz's.
SELECT amount
FROM (
SELECT * ,
SUM(amount) OVER (ORDER BY amount ASC) AS total
from demo
) T
WHERE total <= 6
A fiddle in the hand... http://sqlfiddle.com/#!6/b8506/6

SQL query to select percentage of total

I have a MSSQL table stores that has the following columns in a table:
Storeid, NumEmployees
1 125
2 154
3 10
4 698
5 54
6 98
7 87
8 100
9 58
10 897
Can someone help me with the SQL query to produce the top stores(storeID) that has 30% of the total emplyees(NumEmployees)?
WITH cte
AS (SELECT storeid,
numemployees,
( numemployees * 100 ) / SUM(numemployees) OVER (PARTITION BY 1)
AS
percentofstores
FROM stores)
SELECT *
FROM cte
WHERE percentofstores >= 30
ORDER BY numemployees desc
Working Demo
Alternative that doesn't use SUM/OVER
SELECT s.storeid, s.numemployees
FROM (SELECT SUM(numemployees) AS [tots]
FROM stores) AS t,
stores s
WHERE CAST(numemployees AS DECIMAL(15, 5)) / tots >= .3
ORDER BY s.numemployees desc
Working Demo
Note that in the second version I decided not to multiply by 100 before dividing. This requires a cast to decimal otherwise it would be implicitly converted to a int resulting in no records returned
Also I'm not completely clear that you want this, but you can add TOP 1 to both queries and it will limit the results to just the one with the greatest # of stores with more than 30%
UPDATE
Based on your comments it sounds to paraphrase Kevin
You want the rows, starting at the store with the most employees and working down until you have at least 30 %
This is difficult because it requires a running percentage and its a bin packing problem however this does work. Note I've included two other test cases (where the percent exactly equals and its just over the top two combined)
Working Demo
DECLARE #percent DECIMAL (20, 16)
SET #percent = 0.3
--Other test values
--SET #percent = 0.6992547128452433
--SET #percent = 0.6992547128452434
;WITH sums
AS (SELECT DISTINCT s.storeid,
s.numemployees,
s.numemployees + Coalesce(SUM(s2.numemployees) OVER (
PARTITION
BY
s.numemployees), 0)
runningsum
FROM stores s
LEFT JOIN stores s2
ON s.numemployees < s2.numemployees),
percents
AS (SELECT storeid,
numemployees,
runningsum,
CAST(runningsum AS DECIMAL(15, 5)) / tots.total
running_percent,
Row_number() OVER (ORDER BY runningsum, storeid ) rn
FROM sums,
(SELECT SUM(numemployees) total
FROM stores) AS tots)
SELECT p.storeID,
p.numemployees,
p.running_percent,
p.running_percent,
p.rn
FROM percents p
CROSS JOIN (SELECT MAX(rn) rn
FROM percents
WHERE running_percent = #percent) exactpercent
LEFT JOIN (SELECT MAX(rn) rn
FROM percents
WHERE running_percent <= #percent) underpercent
ON p.rn <= underpercent.rn
OR ( exactpercent.rn IS NULL
AND p.rn <= underpercent.rn + 1 )
WHERE
underpercent.rn is not null or p.rn = 1

SQL select row-wise increase in amount of running total column

Suppose I have a table with columns (DayId, RunningTotal):
DayId RunningTotal
---------------------
1 25
3 50
6 100
9 200
10 250
How can I select the DayId and the amount the RunningTotal has increased from the previous day? i.e. how can I select:
DayId DayTotal
---------------------
1 25
3 25
6 50
9 100
10 50
The only current method I know is with a while loop I am trying to factor out. Also, the DayId has no regular rules, just that it is some increasing integer value, but it increases by an irregular amount as shown in the example table.
EDIT: using MS SQL Server 2005
with cte as (
select dayid, runningtotal, row_number() over (order by dayid asc) as row_index
from #the_table
)
select cur.dayid, cur.runningtotal - coalesce(prev.runningtotal, 0) as daytotal
from cte cur
left join cte prev on prev.row_index = cur.row_index - 1
(I really wish they'd implemented support for the lead and lag functions in SQL Server :|)
There is probably a more succinct way than this, but try:
select t3.DayId,
case when t4.DayId is null then t3.RunningTotal else t3.RunningTotal - t4.RunningTotal end as DayTotal
from (
select t1.DayId, max(t2.DayId) as PreviousDayId as
from MyTable t1
left outer join MyTable t2 on t2.DayId < t1.DayId
group by t1.DayId
) a
inner join MyTable t3 on a.DayId = t3.DayId
left outer join MyTable t4 on a.PreviousDayId = t4.DayId