Check values in all previous rows in SQL table - sql

I have the following SQL table:
declare #t table(START_DATE datetime,INDEX_ID int, GROSS_SALES_PRICE decimal(10,2));
insert into #t values
('20150619',10000410,38)
,('20170311',10000410,26.49)
,('20170312',10000410,26.49)
,('20170317',10000410,38)
,('20170318',10000410,38)
,('20170321',10000410,38);
I would like to check if there are any temporary changes in GROSS_SALES_PRICE
For example, in this table I have a price 38, then I have two rows with 26.49 and then 38 again. There can be any number of lower price rows so I think I have to check multiple previous rows?
I would like to make third column with value of 1 if this situation happened:

WITH maxPrice AS
(
SELECT INDEX_ID, MAX(GROSS_SALES_PRICE) MaxPrice
FROM #t
GROUP BY INDEX_ID
)
SELECT t.INDEX_ID, t.GROSS_SALES_PRICE,
CASE WHEN GROSS_SALES_PRICE < maxPrice.MaxPrice THEN 1 ELSE 0 END AS [CHANGED]
FROM #t t
INNER JOIN maxPrice
ON maxPrice.INDEX_ID = t.INDEX_ID;
GO
INDEX_ID | GROSS_SALES_PRICE | CHANGED
-------: | :---------------- | ------:
10000410 | 38.00 | 0
10000410 | 26.49 | 1
10000410 | 26.49 | 1
10000410 | 38.00 | 0
10000410 | 38.00 | 0
10000410 | 38.00 | 0
dbfiddle here

Related

How to show values that has a suitable pair in sql server

I have a table like this
---------------------------------------------
Id | TransactionId | Amount | Account| crdr |
---------------------------------------------
1 | 1 | 100 | 11111 | 1 |
2 | 2 | 130 | 13133 | 1 |
3 | 1 | 100 | 12111 | 2 |
4 | 2 | 130 | 13233 | 2 |
5 | 2 | 110 | 12122 | 1 |
What I need to display is, show these records as pairs (I have grouped them by transactionid, Amount).
SELECT TransactionId ,Amount , Account, CrDr
FROM Table1 ORDER BY TransactionId ASC,Amount ASC, CrDr ASC
But I want to ignore the records which dont have a pair, as a Example for this above records set result should be like this
---------------------------------------------
TransactionId | Amount | Account| crdr |
---------------------------------------------
1 | 100 | 11111 | 1 |
1 | 100 | 12111 | 2 |
2 | 130 | 13133 | 1 |
2 | 130 | 13233 | 2 |
Can someone suggest a solution for this.
You could use a correlated subquery with a NOT EXISTS condition to ensure that another record exists with the same TransactionId and Amount:
SELECT TransactionId ,Amount , Account, CrDr
FROM Table1 t
WHERE EXISTS (
SELECT 1
FROM Table1 t1
WHERE
t.id <> t1.id
AND t.TransactionId = t1.TransactionId
AND t.Amount = t1.Amount
)
ORDER BY TransactionId ASC,Amount ASC, CrDr ASC
Demo on DB Fiddle:
TransactionId | Amount | Account | CrDr
------------: | -----: | ------: | ---:
1 | 100 | 11111 | 1
1 | 100 | 12111 | 2
2 | 130 | 13133 | 1
2 | 130 | 13233 | 2
Try this:
DECLARE #DataSource TABLE
(
[Id] INT
,[TransactionId] INT
,[Amount] INT
,[Account] INT
,[crdr] INT
);
INSERT INTO #DataSource ([Id], [TransactionId], [Amount], [Account], [crdr])
VALUES (1, 1, 100, 11111, 1)
,(2, 2, 130, 13133, 1)
,(3, 1, 100, 12111, 2)
,(4, 2, 130, 13233, 2)
,(5, 2, 110, 12122, 1);
WITH DataSource AS
(
SELECT *
,COUNT(*) OVER (PARTITION BY [TransactionId], [Amount]) AS [Count]
FROM #DataSource
)
SELECT *
FROM DataSource
WHERE [Count] = 2
ORDER BY TransactionId ASC,Amount ASC, CrDr ASC;
Try this: This this simplest solution of this problem
;with cte
as
(
select TransactionId, Amount
from Table1
group by TransactionId, Amount
having count(*) > 1
)
select *
from Table1 t
inner join cte c on t.TransactionId = c.TransactionId and t.Amount = c.Amount

SQL Get amount paid in statement account in different dates

I have this schema
Item:
| ItemId | Name | Price |
|--------|-------|-------|
| 1 | Item1| 5.00 |
| 2 | Item2| 2.00 |
OrderHeader:
| OrderId| OrderNum| OrderDate |
|--------|---------|------------|
| 1 | ORD1 | 2017-05-10 |
| 2 | ORD2 | 2017-05-12 |
OrderDetails:
|OrderId| ItemId | Total |
--------|--------|---------
| 1 | 1 | 3 |
| 2 | 1 | 2 |
How can I get this result:
|ItemId | OrderId | Paid | Debt |
--------|-----------|----------------
| 1 | 1 | 3 | 2 |
| 1 | 2 | 5 | 0 |
In the result set, the column paid must contains the total of previous payments and plus the new one.
How can I use a Common table expression for example to solve this?
This, you should have provided us:
DECLARE #Item TABLE (Id int, [Name] varchar(15), Price int)
DECLARE #OrderDetails TABLE (OrderId int, ItemId int, Total int)
INSERT INTO #ITEM VALUES (1, 'ITEM1', 5), (2, 'ITEM2', 2)
INSERT INTO #OrderDetails VALUES (1, 1, 3), (2, 1, 2)
This, seems to work, and I think it still has room for improvement:
SELECT OrderId, ItemId, [SUM1], R.Price - [SUM1]
FROM #OrderDetails AS A
LEFT JOIN #Item AS R ON A.ItemId = R.Id
OUTER APPLY (
SELECT SUM(SUB1.TOTAL) AS [SUM1]
FROM #OrderDetails AS SUB1
WHERE SUB1.ItemId = A.ItemId AND SUB1.OrderId <= A.OrderId
) AS B

SUM values in last row

I have table with values
+--------+------------+-------------+
| XPK | Money | NumOfDevices|
+--------+------------+-------------+
| 1 | 1000 | 2 |
| 2 | 2000 | 3 |
| 3 | 3000 | 4 |
+--------+------------+-------------+
Need to sum all values and to enter the asterisk "*" in entire row to separate TOTAL Values from other values, so result need to look something like this
+--------+------------+-------------+
| XPK | Money | NumOfDevice |
+--------+------------+-------------+
| 1 | 1000 | 2 |
| 2 | 2000 | 3 |
| 3 | 3000 | 4 |
|***********************************|
| TOTAL | 6000 | 9 |
+--------+------------+-------------+
Any idea ?
The easiest way for this is to use a UNION selecting the totals from the table:
Select Convert(Varchar (10), XPK) XPK,
Money,
NumOfDevices
From YourTable
Union
Select 'TOTAL' As XPK,
Sum(Money),
Sum(NumOfDevices)
From YourTable
Order By Case When XPK = 'TOTAL' Then 1 Else 0 End, XPK
Another method of doing this would be to use a GROUP BY WITH ROLLUP
Select Case When Grouping(XPK) = 1
Then 'TOTAL'
Else Convert(Varchar (10), XPK)
End As XPK,
Sum(Money) Money,
Sum(NumOfDevices) NumOfDevices
From YourTable
Group By XPK With Rollup
Order By Grouping(XPK)
IN Table ERP System SAP
select B.ItemCode as'Item No.',B.Dscription as'Item Description',B.Quantity,B.Price as'Sale Amt',B.LineTotal as'Total'
from ODLN A
inner join DLN1 B On A.DocEntry=B.DocEntry
union all
select 'Total',convert(nvarchar(10),sum(case when b.Dscription is not null then 1 else 0 end)),sum(b.quantity),sum(b.price),sum(b.lineTotal)
from ODLN A
inner join DLN1 B On A.DocEntry=B.DocEntry

get the value from the previous row if row is NULL

I have this pivoted table
+---------+----------+----------+-----+----------+
| Date | Product1 | Product2 | ... | ProductN |
+---------+----------+----------+-----+----------+
| 7/1/15 | 5 | 2 | ... | 7 |
| 8/1/15 | 7 | 1 | ... | 9 |
| 9/1/15 | NULL | 7 | ... | NULL |
| 10/1/15 | 8 | NULL | ... | NULL |
| 11/1/15 | NULL | NULL | ... | NULL |
+---------+----------+----------+-----+----------+
I wanted to fill in the NULL column with the values above them. So, the output should be something like this.
+---------+----------+----------+-----+----------+
| Date | Product1 | Product2 | ... | ProductN |
+---------+----------+----------+-----+----------+
| 7/1/15 | 5 | 2 | ... | 7 |
| 8/1/15 | 7 | 1 | ... | 9 |
| 9/1/15 | 7 | 7 | ... | 9 |
| 10/1/15 | 8 | 7 | ... | 9 |
| 11/1/15 | 8 | 7 | ... | 9 |
+---------+----------+----------+-----+----------+
I've found this article that might help me but this only manipulate one column. How do I apply this to all my column or how can I achieve such result since my columns are dynamic.
Any help would be much appreciated. Thanks!
The ANSI standard has the IGNORE NULLS option on LAG(). This is exactly what you want. Alas, SQL Server has not (yet?) implemented this feature.
So, you can do this in several ways. One is using multiple outer applys. Another uses correlated subqueries:
select p.date,
(case when p.product1 is not null else p.product1
else (select top 1 p2.product1 from pivoted p2 where p2.date < p.date order by p2.date desc)
end) as product1,
(case when p.product1 is not null else p.product1
else (select top 1 p2.product1 from pivoted p2 where p2.date < p.date order by p2.date desc)
end) as product1,
(case when p.product2 is not null else p.product2
else (select top 1 p2.product2 from pivoted p2 where p2.date < p.date order by p2.date desc)
end) as product2,
. . .
from pivoted p ;
I would recommend an index on date for this query.
I would like to suggest you a solution. If you have a table which consists of merely two columns my solution will work perfectly.
+---------+----------+
| Date | Product |
+---------+----------+
| 7/1/15 | 5 |
| 8/1/15 | 7 |
| 9/1/15 | NULL |
| 10/1/15 | 8 |
| 11/1/15 | NULL |
+---------+----------+
select x.[Date],
case
when x.[Product] is null
then min(c.[Product])
else
x.[Product]
end as Product
from
(
-- this subquery evaluates a minimum distance to the rows where Product column contains a value
select [Date],
[Product],
min(case when delta >= 0 then delta else null end) delta_min,
max(case when delta < 0 then delta else null end) delta_max
from
(
-- this subquery maps Product table to itself and evaluates the difference between the dates
select p.[Date],
p.[Product],
DATEDIFF(dd, p.[Date], pnn.[Date]) delta
from #products p
cross join (select * from #products where [Product] is not null) pnn
) x
group by [Date], [Product]
) x
left join #products c on x.[Date] =
case
when abs(delta_min) < abs(delta_max) then DATEADD(dd, -delta_min, c.[Date])
else DATEADD(dd, -delta_max, c.[Date])
end
group by x.[Date], x.[Product]
order by x.[Date]
In this query I mapped the table to itself rows which contain values by CROSS JOIN statement. Then I calculated differences between dates in order to pick the closest ones and thereafter fill empty cells with values.
Result:
+---------+----------+
| Date | Product |
+---------+----------+
| 7/1/15 | 5 |
| 8/1/15 | 7 |
| 9/1/15 | 7 |
| 10/1/15 | 8 |
| 11/1/15 | 8 |
+---------+----------+
Actually, the suggested query doesn't choose the previous value. Instead of this, it selects the closest value. In other words, my code can be used for a number of different purposes.
First You need to add identity column in temporary or hard table then resolved by following method.
--- Solution ----
Create Table #Test (ID Int Identity (1,1),[Date] Date , Product_1 INT )
Insert Into #Test ([Date], Product_1)
Values
('7/1/15',5)
,('8/1/15',7)
,('9/1/15',Null)
,('10/1/15',8)
,('11/1/15',Null)
Select ID , DATE ,
IIF ( Product_1 is null ,
(Select Product_1 from #TEST
Where ID = (Select Top 1 a.ID From #TEST a where a.Product_1 is not null and a.ID<b.ID
Order By a.ID desc)
),Product_1) Product_1
from #Test b
-- Solution End ---

Create New Table From Other Table After Grouping

How can I insert to a table a value from "grouping" other table?
That means I have 2 table with different structure.
The table ORDRE with existed DATA
Table ORDRE:
ORDRE ID | CODE_DEST |
-------------------------
1 | a |
2 | b |
3 | c |
4 | a |
5 | a |
6 | b |
7 | g |
I want to INSERT the value FROM Table ORDRE INTO TABLE VOIT:
ID_VOIT | ORDRE ID | CODE_DEST |
---------------------------------------
1 | 1 | a |
1 | 4 | a |
1 | 5 | a |
2 | 2 | b |
2 | 6 | b |
3 | 3 | c |
4 | 7 | g |
This is my best guess on what you need using only the info available.
declare #Ordre table
(
ordre_id int,
code_dest char(1)
)
declare #Voit table
(
id_voit int,
ordre_id int,
code_dest char(1)
)
insert into #Ordre values
(1,'a'),
(2,'b'),
(3,'c'),
(4,'a'),
(5,'a'),
(6,'b'),
(7,'g')
insert into #Voit
select id_voit, ordre_id, rsOrdre.code_dest
from #Ordre rsOrdre
inner join
(
select code_dest, ROW_NUMBER() over (order by code_dest) as id_voit
from #Ordre
group by code_dest
) rsVoit on rsVoit.code_dest = rsOrdre.code_dest
order by id_voit, ordre_id
select * from #Voit
Working Example.
For the specific data you give as an example, this works:
insert into VOIT
select
case code_dest
when 'a' then 1
when 'b' then 2
when 'c' then 3
when 'g' then 4
else 0
end, orderId, code_dest from ORDRE order by code_dest, orderId
But it kind of sucks because it requires hard-coding in a huge case statement.
Test is here - https://data.stackexchange.com/stackoverflow/q/119442/
What I like more is moving the VOIT ID / Code_Dest associations to a new table, so then you could do an inner join instead.
insert into VOIT
select voit_id, orderId, t.code_dest
from ORDRE t
join Voit_CodeDest t2 on t.code_dest = t2.code_dest
order by code_dest, orderId
Working example of that here - https://data.stackexchange.com/stackoverflow/q/119443/