I have a table with data like:
ID Amount Status
1 15.00 Paid
2 3.00 Paid
3 10.00 Awaiting
4 12.00 Awaiting
The system looks at this table to see if a customer has paid enough for a subscription. This uses a table to record payments. Once a day I need to see if the customer has met this requirement.
The solution looks nothing like the above table as it much more complex, but the issue remain the same and can be broken down to this.
I need to find a way to add the amounts up, but when the amount goes over 20, change the data in the table as follows:
ID Amount Status
1 15.00 Paid
2 3.00 Paid
3 2.00 Paid <= Customer has reached payment level
4 12.00 Cancelled <= Subsequent payment is cancelled
5 8.00 BForward <= Extra money is brought forward
Currently I am using a cursor, but performance is bad, as expected.
Does anyone know of a better way?
Generates the desired results. Not sure why you would want to update the original data (assuming this is transnational data)
Declare #Table table (ID int,Amount money,Status varchar(50))
Insert into #Table values
(1,15.00,'Paid'),
(2,3.00,'Paid'),
(3,10.00,'Awaiting'),
(4,12.00,'Awaiting')
;with cteBase as (
Select *
,SumTotal=sum(Amount) over (Order By ID)
From #Table
), cteExtended as (
Select *
,Forward = IIF(SumTotal>20 and SumTotal-Amount<20,SumTotal-20,0)
,Cancelled = IIF(SumTotal>20 and SumTotal-Amount>20,Amount,0)
From cteBase
)
Select ID,Amount,Status='Paid' from cteExtended Where Forward+Cancelled=0
Union All
Select ID,Amount=Amount-Forward,Status='Paid' from cteExtended Where Forward>0
Union All
Select ID,Amount,Status='Cancelled' from cteExtended Where Cancelled>0
Union All
Select ID=(Select Count(*) from cteBase)+Row_Number() over (Order by ID),Amount=Forward,Status='BForward' from cteExtended Where Forward>0
Order By ID
Returns
ID Amount Status
1 15.00 Paid
2 3.00 Paid
3 2.00 Paid
4 12.00 Cancelled
5 8.00 BForward
Related
Greeting
I am new with SQL Server i have a table Transaction with the attribute Debit, Credit and other columns, i want to calculate balance but i cant use CTE Query
expect result should be like ....
Debit Credit Balance
10,000 0 10,000
0 3,0000 7,000
5,000 0 12,000
previously i did it in mysql using variables as below
SELECT A.Debit,A.Credit, #b := #b + A.Debit - A.Credit AS balance
FROM (SELECT #b := 0.0) AS dummy
CROSS JOIN FinTrans A
but I am new to MSSQL SERVER How do I do it in MSSQLSERVER
Thanks in Advance
In SQL Server 2012, you would use the ANSI standard cumulative sum functions:
select ft.*,
sum(debit - credit) over (order by ??) as balance
from FinTrans ft;
SQL tables represent unordered sets. The ?? is for the column that specifies the ordering for your cumulative sum.
In fact, this might typically look like:
select ft.*,
sum(debit - credit) over (partition by <account id column>
order by <ordering column
) as balance
from FinTrans ft;
That is, this is how you would do the calculation for different accounts at the same time.
Now I add this tables with these columns:
DrugID, BatchNo, ManufacreDate, ExpireDate, Quantity.
Note: (DrugID, BatchNo) constitute the primary key.
For example: there are 2 records as follow:
(101, 1234, 1-7-2014, 1-7-2016, 50)
(101, 7654, 1-7-2015, 1-7-2017, 80)
If, as example, one customer wants 80 item from drug with drugID=101, how could I update the table so that the first record will be removed, the second one will remain but the quantity will be modified to 30?
Any help, please?
The approach to solving this is to calculate the cumulative quantity of each drug. Then compare the cumulative amount to the desired amount to determine the rows that need updating.
The rest is a bit of arithmetic. In SQL Server 2012+, the code looks like:
declare #val int = 80;
with t as (
select t.*,
sum(qty) over (partition by drugid order by batchno) as cumeqty
from t
)
update t
set qty = (case when cumeqty - #val < 0 then 0
else cumeqty - #val
end)
where (cumeqty - #val) < qty;
In earlier versions, you have to work a bit harder to get the cumulative quantity, but the idea is the same.
Here is an example of the code (or something very similar) working in SQL Fiddle.
I need to get an automatic method to link certain number consumptions with a payment.
I have for example in my first table.
Payments
ID Amount
1 $5,000
Then I have the following Table:
Consumptions
ID Amount CreatedDate
1 1000 2015-07-01 13:59
2 1000 2015-07-01 19:15
3 1000 2015-07-02 01:01
4 1500 2015-07-02 08:44
5 1000 2015-07-03 05:00
6 800 2015-07-03 19:57
7 200 2015-07-03 21:32
8 500 2015-07-03 23:48
I want to have a way that considering the $5000 payment amount, it automatically chooses the best combination of consumptions that make up the $5,000 sum.
If SQL is difficult, it can also be done on C#.
You will need a CTE that recursively joins with itself and checks all possible combinations.
with Anchor
(
Select Id, Amount, 0 as Level
From Consumptions
),
with RecursiveJoin
(
Select Id, Amount, Level From Anchor
Where Level = 0
UNION ALL
-- generate all possible permutations of amounts
Select c2.Id, c1.Amount + c2.Amount, Level + 1
From RecursiveJoin c1
Left Join RecursiveJoin c2 on c1.Id < c2.Id -- eliminate self joins and palindromes
)
Select *
From RecursiveJoin c
Join Payments p on c.Amount = p.Amount
I'm not completely confident that my recursion is correct. Hopefully that gets you started on the concept.
I'll leave it to you to add fields that concatenate lists of Id's of consumptions in each recursion.
It will give you multiple matches since multiple combinations of consumptions could match a payment. You could find the one with fewest combinations by keeping count in the recursion.
I have an Excel file where I have Products, and in the same file, I have prices that applied for some products based on a column where I have the code of products where applied.
For example, I have a product with codeAAA123and I have other product with codeAAA124. And I have 2 prices, one for products that start withAAAand another for productAAA124.
So, the price for productAAAmust be the price which applied for products that start withAAAand the price for productAAA124must be the price for product that applied exactly for products with code AAA124 because is the better coincidence. If not finds an exactly coincidence, remove one character and make another search, until find best coincidence.
I don't know how to accomplish this. I was thinking in save products in my table products, and for prices create a temporal table, then with a stored procedure find the best coincidence with something like this:
SELECT Price,
(CASE WHEN code LIKE 'AAA124' THEN 4 ELSE 0 END) +
(CASE WHEN code LIKE 'AAA12' THEN 3 ELSE 0 END) +
(CASE WHEN code LIKE 'AAA1' THEN 2 ELSE 0 END) +
(CASE WHEN code LIKE 'AAA' THEN 1 ELSE 0 END) + as rank
FROM Product
ORDER BY rank DESC
Instead of code hard coded, will be a parameter pass to a stored procedure.
If Anyone could guide me it will be much appreciated.
The code below should find a pretty decent match. You could put it into a scalar function so the price is automatically updated when you import the latest price list into a db table in your server or use it to save the price to the products table if you don't want price changes retroactive.
DECLARE #Prices TABLE (CodeMatch VARCHAR(10), Price MONEY )
DECLARE #Products TABLE (ProductCode VARCHAR(10))
INSERT #Prices VALUES ('AAA124', 10), ('AAA', 20)
INSERT #Products VALUES ('AAA123'), ('AAA124')
SELECT
ProductCode,
( SELECT TOP 1 Price FROM #Prices ORDER BY LEN(REPLACE(ProductCode, CodeMatch, '')) )
FROM #Products
I have a table as follows,
TypeID Name Date
-------------------------------
1 Carrot 1-1-2013
1 Beetroot 1-1-2013
1 Beans 1-1-2013
2 cabbage 1-1-2013
2 potato 1-1-2013
2 tomato 1-1-2013
2 onion 1-1-2013
If need 2 rows then it should return 2 rows from TypeId 1 and 2 rows from TypeId 2.If need the only 4 rows, means I have to get 4 rows from TypeId 1 and 4 rows from TypeId 2
but TypeId 1 has only 3 rows so we need to get only 3 rows for typeId 1
How to do that? Shall I add RowNumber?
For SQL Server;
EDIT: Your question changed slightly;
If you want want a maximum of x items per category, you can use ROW_NUMBER();
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY TypeID ORDER BY Name) rn FROM Table1
)
SELECT TypeID, Name, [Date] FROM cte
WHERE rn <=3 -- here is where your x goes
ORDER BY TypeID;
An SQLfiddle to test with.
You can write your query to order by the TypeID.
Then, if you're using SQL, you could use SELECT TOP N or LIMIT N (depending on the DB), or with TSQL and SQL Server, use TOP(N) to take the top N rows.
If you're using a LINQ based ORM from your C# code, then you can use Take(N), which automatically creates the appropriate query based on the provider details to limit the number of results.
I think you should use a query to select your 3 rows from type 1.....and then the however many rows from type 2 and then add the results together.
;With CTE(TypeID,Name,Date,RowNo)
AS
(
select *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID) from TableVEG
)
Select Top(#noofRows*2) * from CTE where RowNo<=#noofRows order by rowno
The above query worked.. Thank u all... :-)