Get empty values from database table [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I have a database table which has columns with values 1 till 999
But it has some spaces e.g. 1,2,3,4,5,6,11,15 etc...
What would be the best to get the "next number" from this table?
Thanks in advance for your help

one way to do this is to get for every row the prior row, and then check where you are making a step.
This will not perform great, and it is NOT SAFE when more then 1 user is adding new rows !
declare #t table (number int)
insert into #t values (1), (2), (3), (4), (5), (6), (11), (12)
select top 1
(select top 1 t2.number + 1 from #t t2 where t2.number < t.number order by t2.number desc) as prior
from #t t
where number <> (select top 1 t2.number + 1 from #t t2 where t2.number < t.number order by t2.number desc)
order by t.number
The result would be 7
Another option is this
select top 1
t.number + 1
from #t t
left join #t t2 on t.number = t2.number - 1
where t2.number is null
order by t.number
This method might even be faster then the solution of Robin
EDIT
As Daniel pointed out in a comment, this will never return 1 in case the gap happens to be the first row.
To fix this, we can retrieve a value for the first missing row, and add it to our result by use of a union.
select top 1 number
from ( select top 1
t.number + 1 as number
from #t t
left join #t t2 on t.number = t2.number - 1
where t2.number is null
union
select 1 as number
from #t t
where not exists (select 1 from #t t3 where t3.number = 1)
) t
order by t.number
Since the extra query can only retrieve exact one row by an index, this should not affect performance much

You can use a CTE to generate the numbers and then get the first one that does not match with a record....
This work fine as you mentioned that it is not a large table
I have a datatable which has columns with values 1 till 999
Regard the other answers, both are too much faster than this with large tables, but none of them will return the correct value (1) if your input starts on 2 or greater.
I don't know the purpose of this request, but be aware that calculating values this way two users working at same time can get the same value. It can be an issue specially if you want to use this value to be part of a primary key or unique index
;with numbers as (
SELECT 1 as nrstart, MAX(yourcolumn) as nrend FROM yourTable
UNION ALL
SELECT nrstart+1, nrend FROM numbers
WHERE nrstart <= nrend
)
SELECT TOP 1 nrstart
FROM numbers
WHERE NOT EXISTS (SELECT 1 FROM yourTable WHERE yourcolumn = numbers.nrstart)
ORDER BY nrStart
OPTION (MAXRECURSION 0);

You want the first number, where that number plus one is not in the table.
SELECT TOP 1 (Number + 1) FROM myTable a WHERE NOT EXISTS
(SELECT * FROM myTable b WHERE b.Number = a.Number + 1)
ORDER By Number
As mentioned in various comments, this sort of thing should be done in a transaction if there's any risk of a second user filling the gap while the first is looking for it.

Related

How do I group T-SQL set by a flag bigint column

I'm working on a project where efficiency of the search functionality is critical.
I have several flag columns (like enum flags in c#). Searching on this data is super fast (3 milliseconds round trip) but I've come-a-cropper now I have to perform group counts.
So, I have an item 'A' that contains Red (1), White (8) and blue (64) so the 'Colours' column holds the number 73.
To search I can search for items with red with this
Declare #colour int
set #colour = 1
Select *
From Items
Where (Colour & #colour) > 0
That works great. Now I have to group it (also super fast)
So if I have 8 items in total, 5 contain red, 3 contain white and 7 contain blue the results would look like:
Colour Qty
------------------
1 5
8 3
64 7 ( I don't have to worry about the name )
So: Is there any way I can take the number 73 and bitwise split it into groups?
(Part 2: How do I translate that into Linq to SQL?)
Any advise would be appreciated
Thanks ^_^
Ok - I think I've worked out the best solution:
I tried a view with a cte:
with cte as (
select cast(1 as bigint) as flag, 1 pow
union all
select POWER(cast(2 as bigint),pow), pow + 1
from cte
where flag < POWER(cast(2 as bigint),62)
)
, cte2 as (
select flag from cte
union select -9223372036854775808
)
but that was too slow so now I have made it into a static table. I join with a bitwise '&':
select Flag, Count(*)
From FlagValues fv
inner join Items i on (fv.Flag & i.Colour)
Much faster ^_^

Last_value with IGNORE NULLS in SQL Server

I have a time series that with null values. I want to be replace each null value with the most recent non-non value. From what I've researched, Oracle SQL can easily accomplish this using Last_value with IGNORE NULLS. Is there a similar way to accomplish this using SQL Server 2016? Otherwise I'm just going to code it using C#, but felt using SQL would be faster, cleaner, and easier.
Sec SCORE
1 Null
2 Null
3 5
4 Null
5 8
6 7
7 Null
Should be replaced with:
Sec SCORE
1 Null
2 Null
3 5
4 5
5 8
6 7
7 7
You can do this with two cumulative operations:
select t.*,
coalesce(score, max(score) over (partition by maxid)) as newscore
from (select t.*,
max(case when score is not null then id end) over (order by id) as maxid
from t
) t;
The innermost subquery gets the most recent id where there is a value. The outermost one "spreads" that value to the subsequent rows.
If you actually want to update the table, you can incorporate this easily into an update. But, Oracle cannot do that (easily), so I'm guessing this is not necessary....
If performance is an issue, I suggest the solution from this article:
The Last non NULL Puzzle
His final solution, while dense, does perform excellently with a linear query plan without any joins. Here is an example implementation I've used which carries the last customer name through a type2 scd staging table. In this staging table, NULL represents no update, and '*** DELETED ***' represents an explicit set to NULL. The following cleans this up to resemble an actual SCD record excellently:
WITH [SampleNumbered] AS (
SELECT *, ROW_NUMBER() OVER ( PARTITION BY [SampleId] ORDER BY [StartDatetime] ) AS [RowNumber]
FROM [dbo].[SampleDimStage]
), [SamplePrep] AS (
SELECT [SampleId]
, [StartDatetime]
, CAST([RowNumber] AS BINARY(8)) + CAST([SampleGroupId] AS VARBINARY(255)) AS [BinarySampleGroupId]
, CAST([RowNumber] AS BINARY(8)) + CAST([SampleStatusCode] AS VARBINARY(255)) AS [BinarySampleStatusCode]
FROM [SampleNumbered]
), [SampleCleanUp] AS (
SELECT [SampleId]
, [StartDatetime]
, CAST(SUBSTRING(MAX([BinarySampleGroupId]) OVER( PARTITION BY [SampleId] ORDER BY [StartDatetime] )
, 9, 255) AS VARCHAR(255)) AS [LastSampleGroupId]
, CAST(SUBSTRING(MAX([BinarySampleStatusCode]) OVER( PARTITION BY [SampleId] ORDER BY [StartDatetime] )
, 9, 255) AS VARCHAR(255)) AS [LastSampleStatusCode]
, LEAD([StartDatetime]) OVER( PARTITION BY [SampleId] ORDER BY [StartDatetime] ) AS [EndDatetime]
FROM [SamplePrep]
)
SELECT CAST([SampleId] AS NUMERIC(18)) AS [SampleId]
, CAST(NULLIF([sc].[LastSampleGroupId],'*** DELETED ***') AS NUMERIC(18)) AS [GroupId]
, CAST(NULLIF([sc].[LastSampleStatusCode],'*** DELETED ***') AS CHAR(3)) AS [SampleStatusCode]
, [StartDatetime]
, [sc].[EndDatetime]
FROM [SampleCleanUp] [sc];
If your sort key is some sort of integer, you can completely skip the first CTE and cast that directly to binary.

Select unique random rows from SQL Server table but always duplicates

i am not the best with sql but i try my best to get my Problems done. I have a table "just" which is filled with Columns ( ID (PK, Identity), Char, Serv , Random ) . Now i want to select a random row from this table and insert it into the Table "f_WinGet". So far all my Procedures take this Step fine , but i always get Duplicates in the second table.
First table : 84 rows
Second table: needed 35 random out of 84.
I have tried many other ways but i always get the same result. All my Procedure for random are binded to a Button i a C# Programm. All is working fine so far , but i always have some Duplicates of Rows in my Table.
INSERT INTO f_TWinGet
SELECT TOP 1 Percent Char, Serv, Random
FROM ( select distinct Char, Serv, Random from dbo.just) as derived1
ORDER BY CHECKSUM(NEWID())
It would be nice , if anyone hase an Idea how i can fix my Problem. I am still trying , but all what i get are always the same result.
It you want to insert 35 rows, do it all at once:
INSERT INTO f_TWinGet(char, serv, random)
SELECT TOP 35 Char, Serv, Random
FROM (select distinct Char, Serv, Random
from dbo.just
) derived1
ORDER BY CHECKSUM(NEWID());
If you really want to do them one at a time, I would suggest using not exists:
INSERT INTO f_TWinGet(char, serv, random)
SELECT TOP 1 Char, Serv, Random
FROM (select distinct Char, Serv, Random
from dbo.just
) d
WHERE not exists (select 1 from f_TWinGet f where t.char = f.char and t.serv = f.serv and t.random = f.random)
ORDER BY CHECKSUM(NEWID());
Note that char is a reserved word, so it should be in square braces. I am leaving the names you have have them in your query.
With a table as small as yours you can use something like:
INSERT INTO f_TWinGet
SELECT TOP 1 j.Char, j.Serv, j.Random
FROM dbo.just j
LEFT JOIN f_TWinGet f
ON f.Char = j.Char
AND j.Serv = f.Serv
AND j.Random = f.Random
WHERE f.Char IS NULL
ORDER BY NEWID()
This way making sure that the values you're trying to insert is not on the final table.

picking last records inserted into table [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have inserted 4 records into table1, and then 5 records and then 3 records.
Now I want to pick up last 3 records or say any number of records but inserted at last. How I will get those ?
Actually scenario is that in gridview 1 user would select say 3 records by help of checkbox field and then these 3 records will be inserted in to table1 and then store procedure will pick these last inserted 3 reocrds and assign it to RDLC report. All things are done but just don't know how to pick last inserted any number of records.
By definition, a table is an unordered set of rows. There is no way to ask SQL Server which row was inserted last unless you are doing so in the same batch as the insert. For example, if your table has an IDENTITY column, you can say:
INSERT dbo.table(column) values (...)
SELECT SCOPE_IDENTITY();
But that too will give you the last first identity column.
What you can do here is that you can take the help of timestamp and define that in a separate column of the table.
ALTER TABLE dbo.table ADD DateInserted DEFAULT CURRENT_TIMESTAMP;
Define stored procedure with the #lastrows count that you will store in your service layer to call.
CREATE PROC sp_GetLastInsertedRows(#lastrows int)
AS
;WITH x AS (SELECT *, r = ROW_NUMBER() OVER (ORDER BY DateInserted DESC)
FROM dbo.table)
SELECT * FROM x WHERE r <= N;
This way you get the last N number of rows inserted in the last transaction.
you can use below menioned query
SELECT column_name FROM table_name
ORDER BY column_name DESC
LIMIT 3;
Okay, so you're going to need something a bit more flexible. Right now you may have just one user, and right now you may be running the report immediately after executing the INSERT statements, but what you really need to know is what rows are new since the last time you looked.
One good way of doing this is adding a DATETIME NULL field to the row; let's call it processed_date. This field will be updated by the stored procedure that picks them up for the report. Something like this:
SELECT * FROM tbl1
INTO #report_tbl
WHERE processed_date IS NULL
UPDATE tbl1
SET processed_date = GETDATE()
WHERE id_field IN (
SELECT id_field
FROM #report_tbl
)
Now you are sure to pick up the rows that "haven't been looked at."

Get the Rows separately based on the ID in sql

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... :-)

Categories

Resources