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.
Related
In my application, I fetch all tables in Database.
User will select table name and colum names to be masked.
Now i want to update sql table-columns with random generate string , which must be unique for each row without using primary key or unique key.
For example, In my Employeedb i have a table Employee.
Out of columns in Employee table, i want to mask data in name and city columns.
If table conatins 1000 rows, i want change name and city columns with 1000 unique values each. That means i want to update row by row.
Name Address City
Raghav flatno34 mumbai
Ranveer flatno23 chennai
This is orignal data
Name Adress City
Sbgha flatno34 mmjgujj
Lkhhvh flatno23 huughh
This is expected out
The table have primarykey sometimes.. There may be chances of not having primary key.
I have one more qn, I have this expected output in a datatable. Since i cannot predefine the table name and number of fields how will i write an update qry.
I think you will find my blog post entitled How to pre-populate a random strings pool very helpful for this requirement.
(Inspired by this SO answer from Martin Smith, to give credit where credit is due)
It describes an inline table valued user defined function that generates a table of random values, which you can use to update your data.
However, it does not guarantee uniqueness of these values. For that, you must use DISTINCT when selecting from it.
One problem you might encounter because of that is having a result with less values than you generated, but for 1,000 records per table as you wrote in the question it's probably not going to be a problem, since the function can generate up to 1,000,000 records each time you call it.
For the sake of completeness, I'll post the code here as well, but you should probably read the post at my blog.
Also, there's another version of this function in another blog post entitled A more controllable random string generator function for SQL Server - which gives you better control over the content of the random strings - i.e a string containing only numbers, or only lower digits.
The first thing you need to do is create a view that will generate a new guid for you, because this can't be done inside a user-defined function:
CREATE VIEW GuidGenerator
AS
SELECT Newid() As NewGuid
Then, the function code: (Note: this is the simpler version)
CREATE FUNCTION dbo.RandomStringGenerator
(
#Length int,
#Count int -- Note: up to 1,000,000 rows
)
RETURNS TABLE
AS
RETURN
-- An inline tally table with 1,000,000 rows
WITH E1(N) AS (SELECT N FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) V(N)), -- 10
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --100
E3(N) AS (SELECT 1 FROM E2 a, E2 b), --10,000
Tally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY ##SPID) FROM E3 a, E2 b) --1,000,000
SELECT TOP(#Count) (
SELECT TOP (#Length) CHAR(
-- create a random number from a guid using the GuidGenerator view, mod 3.
CASE Abs(Checksum(NewGuid)) % 3
WHEN 0 THEN 65 + Abs(Checksum(NewGuid)) % 26 -- Random upper case letter
WHEN 1 THEN 97 + Abs(Checksum(NewGuid)) % 26 -- Random lower case letter
ELSE 48 + Abs(Checksum(NewGuid)) % 10 -- Random digit
END
)
FROM Tally As t0
CROSS JOIN GuidGenerator
WHERE t0.n != -t1.n -- Needed for the subquery to get re-evaluated for each row
FOR XML PATH('')
) As RandomString
FROM Tally As t1
Then, you can use it like this to get a distinct random string:
SELECT DISTINCT RandomString
FROM dbo.RandomStringGenerator(50, 5000);
Im trying to make a quote for my winform I have a total of 100 records. I created it like this
CREATE TABLE quote (
quote_id numeric identity primary key,
quote_quote varchar(500) not null,
quote_from varchar(100) not null,
)
Now I get the display I wanted when I display it in my winform, but I think that everyday a new quote would replace the other is nice, rather than just every run a different quote will display. I query it like this
SELECT TOP 1 quote_quote,quote_from FROM quotes ORDER BY NEWID()
How can I do that every day, that query will fire or any other suggestion?
There are a few ways to do this. One option is the following, which will cycle through a new quote each day:
SELECT quote_quote, quote_from FROM QUOTE
ORDER BY QUOTE_ID
OFFSET (SELECT CAST(GETDATE() AS INT) % COUNT(*) FROM QUOTE) ROWS
FETCH NEXT 1 ROW ONLY;
The subquery SELECT CAST(GETDATE() AS INT) % COUNT(*) FROM QUOTE casts the current date to an integer (days since 1900-01-01) modulates by the number of rows in the quote table. This will be a number between 0 and N-1, where N is the number of rows in the quotes table. The query is offset by this number of rows and fetches only one row; the effect is to cycle through the quotes a day at a time.
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.
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
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