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.
Related
I have 2 tables , one called "Booking" and another called "Assignments" there is no relation between these two tables
"Booking" tables contains columns "Resource" ,"start date", "end date", "hours"
"Assignments" table contains columns "Resource" , "start date" , "end date", "hours"
"Booking" table rows are daily records , means start and end date will always be same and hours will be less than 8(working hours in a day)
"Assignment" table rows can be multi day records , means start and end date can be same or different , example start date 01-02-2022 and end date 03-02-2022 and hours can be 24 hours(max 8 hours per day)
Now I have to find all booking rows for a "Resource" , which do not have equivalent assignment row for a particular day and hours
There can be complex scenario in which booking for "resource a" for "1-2-2022" is for "8 hours" , but assignment row for same date and resource is just 6 hours , so I need to find those missing hours too.
What is the fastest and most efficient way to do it? Records can be in millions and preferred programming language is C# , if C# cannot give me a way to process all this in Max 30 minutes ,other approaches are also welcome , like storing these 2 tables in a SQL database and run a query on it , to get results in a 3rd table
Thanks for your help
I would use the backend to do such processes.
An index on a Checksum on each table would be efficient.
Start by creating the Booking and Assignment tables.
Add the checksums:
ALTER TABLE Booking
ADD Booking_Checksum AS CHECKSUM( [Resource] ,[start date], [end date], [hours]) PERSISTED;
ALTER TABLE Assignment
ADD Assignment_Checksum AS CHECKSUM( [Resource] ,[start date], [end date], [hours]) PERSISTED;
Add indexes:
CREATE NONCLUSTERED INDEX [IX_Booking_Checksum] ON [dbo].[Booking]
( Booking_Checksum ASC )
CREATE NONCLUSTERED INDEX [IX_Assignment_Checksum] ON [dbo].[Assignment]
( Assignment_Checksum ASC )
All in Booking but not Assignment:
Select b.*
From Booking b
left join Assignment a on b.Booking_Checksum = a.Assignment_Checksum
where a.Assignment_Checksum is null
All in Assignment but not in Booking:
Select a.*
From Assignment a
left join Booking b on b.Booking_Checksum = a.Assignment_Checksum
where b.Booking_Checksum is null
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);
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 have a table in my DB which contains Date and Time separately in columns for a Time Table so for Displaying it as a Single one in the front end I had joined Date and Time Column and Inserted into Temporary table and Unpivoted it,but the Pk_id is same for both the Unpivoted Columns so in the Front end in the Drop down box when I select the item in the Index say at 6 in DDL after a postback occur it will return to Index 1 in DDL.So,is there a way to put Serial number for the Unpivoted columns, My Unpivot Query is,
Select * from
(
Select pk_bid,No_of_batches,Batch1,Batch2,Batch3,Batch4, from #tempbatch
) as p
Unpivot(Batchname for [Batches] in([Batch1],[Batch2],[Batch3],[Batch4])) as UnPvt
In the above query pk_bid & No_of_Batches is same so If I put Rownumber() Partition by pk_bid Order by pk_bid or Rownumber() Partition by No_of_Batches Order by No_of_Batches it gives the 1,1 only as it is same.
I had solved My above Problem like this,
I had created another Temporary table and created Serial Number with the column in that table with differant values the Query I had done is,
Create Table #Tempbatch2
(
pk_bid int,
No_of_batches int,
Batchname Varchar(max),
[Batches] Varchar(max)
)
Insert Into #Tempbatch2
Select * from
(
Select pk_batchid,No_of_batches,Batch1,Batch2,Batch3,Batch4 from #tempbatch
) as p
Unpivot(Batchname for [Batches] in([Batch1],[Batch2],[Batch3],[Batch4])) as UnPvt
Select Row_number() OVER(ORDER BY (Batchaname)) as S_No,pk_bid,No_of_batches,Batchname,[Batches] from #Tempbatch2
I have a database, with a table which has around 2.500.000 records. I am fetching around 150.000 records, with 2 different queries to test. First one returns results between 30 seconds and 1 minutes. But the second one, responds in between 3 - 4 minutes which is very weird. The only thing changes is first one doesn't use parameter but second one does. I am running both from C#. For security issues I want to use parametered one but I couldn't understand why does it take so much time. Any help will be appreciated.
First query:
DECLARE #page INT=3
DECLARE #pagesize INT=300
string sql = "SELECT Col1,Col2,Col3 FROM
(SELECT ROW_NUMBER() OVER(ORDER BY Col1) AS rownumber,Col1,Col2,Col3";
sql += " FROM my_table WHERE Col1 LIKE '" + letter + "%') as somex
WHERE rownumber >= (#page-1)*(#pagesize)";
sql += "AND rownumber <=(#page)*#pagesize;
SELECT COUNT(*) FROM my_table WHERE col1 LIKE '" + letter + "%'";
Second query:
DECLARE #page INT=3
DECLARE #pagesize INT=300
DECLARE #starting VARCHAR(10)='be'
string sql = "SELECT Col1,Col2,Col3FROM
(SELECT ROW_NUMBER() OVER(ORDER BY Col1) AS rownumber,Col1,Col2,Col3";
sql += " FROM my_table WHERE Col1 LIKE #letter+'%') as somex
WHERE rownumber >= (#page-1)*(#pagesize)";
sql += "AND rownumber <=(#page)*#pagesize; SELECT COUNT(*)
FROM my_table WHERE col1 LIKE #letter+'%'";
My server is 16GB Ram, 4 real 4 virtual CPU, Sata disks.
Edit: Col1 is Clustered and Non-clustered index.
Progress: It turns out that these queries work well on another server. But this confuses me more. Could it be some setting from SQL Server?
As I said in a comment, it sounds like parameter sniffing, but in the interest of being helpful I thought I'd expand on that. There are a number of articles on the web that
go into a lot more detail than I will, but the long and the short of parameter sniffing is that SQL-Server has cached an execution plan based on a value for the parameter that does not yield the best execution plan for the current value.
Supposing that Col1 has a nonclustered index on, but does not include col2 or col3 as non key columns then
SQL-Server has two options, it can either do a clustered index scan on My_Table to get all the rows where Col1 LIKE #letter+'%', or it can search the index on Col1 then do a bookmark lookup on the clustered index to get the values
for each row returned by the index. I can't quite remember off the top of my head at what point SQL-Server switches between the two based on the estimated row count, it is at quite a low percentage, so I am fairly sure that if you are returning 150,000 records
out of 2,500,000 the optimiser will go for a clustered index scan. However, if you were only returning a few hundred rows then a bookmark lookup would be preferable.
When you don't use parameters SQL-Server will create a new execution plan each time it is executed, and produce the best execution plan for that parameter (assuming your statistics are up to date), when you do use a paramter the first time they query is run sql-server creates a plan
based on that particular parameter value, and stores that plan for later use. Each subsequent time the query is run sql-server recognises that the query is the same so doesn't recompile it. This means though that if the first time the query was run it was for
a parameter that returned a low number of rows then the bookmark lookup plan will be stored. Then if the next time the query is run it is passed for a value that returns a high number of rows where the optimal plan is a clustered index scan then the query is still executed using the suboptimal bookmark lookup and
will result in a longer execution time. This could of course also be true the other way round. There are a number of ways to get around parameter sniffing, but since your query is not very complex the compile time will not be significant, especially in comparison to the 30 seconds you say this query is taking
to run even at its best, so I would use the OPTION RECOMPILE Query hint:
SELECT Col1, Col2, Col3
FROM ( SELECT ROW_NUMBER() OVER(ORDER BY Col1) AS rownumber,Col1,Col2,Col3
FROM my_table
WHERE Col1 LIKE #letter+'%'
) as somex
WHERE rownumber >= (#page-1)*(#pagesize)
AND rownumber <= (#page) * #pagesize
OPTION (RECOMPILE);
SELECT COUNT(*)
FROM my_table
WHERE Col1 LIKE #letter+'%'
OPTION (RECOMPILE);
The reason that when you tried this on a new server that it executed fine is that the first time it was run on the new server the parameterised query had to be compiled, and the plan generated was suitable to value of the parameter provided.
One final point, if you are using SQL_Server 2012 then you could use OFFSET/FETCH to do your paging:
SELECT Col1, Col2, Col3
FROM My_table
WHERE Col1 LIKE #letter+'%'
ORDER BY Col1 OFFSET (#page-1) * (#pagesize) ROWS FETCH NEXT #pagesize ROWS ONLY;