Efficiently checking if more than one row exists in a recordset - sql

I'm using SQL Server 2008 R2, and I'm trying to find an efficient way to test if more than 1 row exists in a table matching a condition.
The naive way to do it is a COUNT:
IF ( SELECT COUNT(*)
FROM Table
WHERE Column = <something>
) > 1 BEGIN
...
END
But this requires actually computing a COUNT, which is wasteful. I just want to test for more than 1.
The only thing I've come up with is a COUNT on a TOP 2:
IF ( SELECT COUNT(*)
FROM ( SELECT TOP 2 0 x
FROM Table
WHERE Column = <something>
) x
) > 1 BEGIN
...
END
This is clunky and requires commenting to document. Is there a more terse way?

If you have a PK in the table that you're checking for >1 row, you could nest another EXISTS clause. Not sure if this is faster, but it achieves your record result. For example, assuming a Station table with a PK named ID that can have zero-to-many Location table records with a PK named ID, Location has FK StationID, and you want to find the Stations with at least two Locations:
SELECT s.ID
FROM Station s
WHERE EXISTS (
SELECT 1
FROM Location L
WHERE L.StationID = s.ID
AND EXISTS (
SELECT 1
FROM Location L2
WHERE L2.StationID = L.StationID
AND L2.ID <> L.ID
)
)

I have the following solution to share, which may be lighter performance-wise.
I suppose that you are trying to fetch the first record and process it once you make sure that your SQL selection returns a single record. Therefore, go on and fetch it, but once you do that, try to fetch the next record right away, and if successful, you know that more than one record exists, and you can start your exception processing logic. Otherwise, you can still process your single record.

Related

Update a single row in a table in SQL

So, I am creating a new table that gets populated from another table. NewTableA.ColA is getting populated from an existing OldTableB.ColB
Source query that populates NewTableA.ColA:
SELECT TOP (1) EXEC_END_TIME
FROM CR_STAT_EXECUTION AS cse
WHERE (EXEC_NAME = 'ETL')
ORDER BY EXEC_END_TIME DESC
Destination Table (NewTableA.ColA) When scripted out:
SELECT TOP 1 [EXEC_END_TIME]
FROM [SSISHelper].[dbo].[ETLTimeCheck]
ORDER BY EXEC_END_TIME DESC
The problem I am facing is, I only want to have 1 row in the NewTableA.ColA that updates the current value in the ColA from the other table. I already setup an SSIS job to populate the table every day from OldTableB.ColB... I just couldn't figure out how I can only update 1 row from OldTableB.ColB?
Thanks.
Use IF condition in SQL:
Example:
IF EXISTS (SELECT * FROM EXEC_END_TIME WHERE COLUMNX='xValue')
BEGIN
(...update...i guess)
END
ELSE
BEGIN
(...insert...i guess)
END

Loop through table and update a specific column

I have the following table:
Id
Category
1
some thing
2
value
This table contains a lot of rows and what I'm trying to do is to update all the Category values to change every first letter to caps. For example, some thing should be Some Thing.
At the moment this is what I have:
UPDATE MyTable
SET Category = (SELECT UPPER(LEFT(Category,1))+LOWER(SUBSTRING(Category,2,LEN(Category))) FROM MyTable WHERE Id = 1)
WHERE Id = 1;
But there are two problems, the first one is trying to change the Category Value to upper, because only works ok for 1 len words (hello=> Hello, hello world => Hello world) and the second one is that I'll need to run this query X times following the Where Id = X logic. So my question is how can I update X rows? I was thinking in a cursor but I don't have too much experience with it.
Here is a fiddle to play with.
You can split the words apart, apply the capitalization, then munge the words back together. No, you shouldn't be worrying about subqueries and Id because you should always approach updating a set of rows as a set-based operation and not one row at a time.
;WITH cte AS
(
SELECT Id, NewCat = STRING_AGG(CONCAT(
UPPER(LEFT(value,1)),
SUBSTRING(value,2,57)), ' ')
WITHIN GROUP (ORDER BY CHARINDEX(value, Category))
FROM
(
SELECT t.Id, t.Category, s.value
FROM dbo.MyTable AS t
CROSS APPLY STRING_SPLIT(Category, ' ') AS s
) AS x GROUP BY Id
)
UPDATE t
SET t.Category = cte.NewCat
FROM dbo.MyTable AS t
INNER JOIN cte ON t.Id = cte.Id;
This assumes your category doesn't have non-consecutive duplicates within it; for example, bora frickin bora would get messed up (meanwhile bora bora fickin would be fine). It also assumes a case insensitive collation (which could be catered to if necessary).
In Azure SQL Database you can use the new enable_ordinal argument to STRING_SPLIT() but, for now, you'll have to rely on hacks like CHARINDEX().
Updated db<>fiddle (thank you for the head start!)

SQL loop through a table and find the next part record

Not sure where to start on this one. I inheriated a table that has a list of part numbers that are are active and inactive. If the part number is inactive, they enter the next valid part number. If the part number is active there is no Next PartNumber. They want to search on a Part Number and find all of the next part numbers that match.
Basically the table looks like this.
PartNumber Varchar(20), Active Varchar(3), NextPartNumber Varchar(20).
Problem is I do not know how many part numbers are in the chain. Here is a sample of the data:
100X No XYZ
XYZ No 45A6
45A6 Yes
QWER No RT98
RT98 No POUL1
POUL1 No N9HGT
N9HGT No FGH12
FGH12 Yes
I can write a query like this, but since I don't know how many part numbers there are, this won't work.
Select A.PartNumber, A.NextPartNumber, B.PartNumber, B.NextPartNumber, C.PartNumber, C.NextPartNumber
FROM tblPartTable as A
inner join
tblPartTable as B
on A.PartNumber = B.NextPartNumber
inner join
tblPartTable as C
on B.PartNumber = C.NextPartNumber
where A.PartNumber = '100X'
With SQL Server (which I'm assuming you're talking about since your earlier questions have been about it), you can use a recursive common table expression to easily get the searched for part and all its successors, there is no need to loop manually;
WITH cte AS (
-- Base condition, where do we start the search?
SELECT t.* FROM tblPartTable t WHERE t.PartNumber = '100X'
UNION ALL
-- Continue condition, how do we find the next part from the current one?
SELECT t.* FROM tblPartTable t JOIN cte ON t.PartNumber = cte.NextPartNumber
)
SELECT partnumber, active FROM cte;
An SQLfiddle to test with.
The same query works on most RDBMS's except MySQL.

Fastest check if row exists in PostgreSQL

I have a bunch of rows that I need to insert into table, but these inserts are always done in batches. So I want to check if a single row from the batch exists in the table because then I know they all were inserted.
So its not a primary key check, but shouldn't matter too much. I would like to only check single row so count(*) probably isn't good, so its something like exists I guess.
But since I'm fairly new to PostgreSQL I'd rather ask people who know.
My batch contains rows with following structure:
userid | rightid | remaining_count
So if table contains any rows with provided userid it means they all are present there.
Use the EXISTS key word for TRUE / FALSE return:
select exists(select 1 from contact where id=12)
How about simply:
select 1 from tbl where userid = 123 limit 1;
where 123 is the userid of the batch that you're about to insert.
The above query will return either an empty set or a single row, depending on whether there are records with the given userid.
If this turns out to be too slow, you could look into creating an index on tbl.userid.
if even a single row from batch exists in table, in that case I
don't have to insert my rows because I know for sure they all were
inserted.
For this to remain true even if your program gets interrupted mid-batch, I'd recommend that you make sure you manage database transactions appropriately (i.e. that the entire batch gets inserted within a single transaction).
INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count
FROM batch
WHERE NOT EXISTS (
SELECT * FROM target t2, batch b2
WHERE t2.userid = b2.userid
-- ... other keyfields ...
)
;
BTW: if you want the whole batch to fail in case of a duplicate, then (given a primary key constraint)
INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count
FROM batch
;
will do exactly what you want: either it succeeds, or it fails.
If you think about the performace ,may be you can use "PERFORM" in a function just like this:
PERFORM 1 FROM skytf.test_2 WHERE id=i LIMIT 1;
IF FOUND THEN
RAISE NOTICE ' found record id=%', i;
ELSE
RAISE NOTICE ' not found record id=%', i;
END IF;
as #MikeM pointed out.
select exists(select 1 from contact where id=12)
with index on contact, it can usually reduce time cost to 1 ms.
CREATE INDEX index_contact on contact(id);
SELECT 1 FROM user_right where userid = ? LIMIT 1
If your resultset contains a row then you do not have to insert. Otherwise insert your records.
select true from tablename where condition limit 1;
I believe that this is the query that postgres uses for checking foreign keys.
In your case, you could do this in one go too:
insert into yourtable select $userid, $rightid, $count where not (select true from yourtable where userid = $userid limit 1);

Check whether a table contains rows or not sql server 2005

How to Check whether a table contains rows or not sql server 2005?
For what purpose?
Quickest for an IF would be IF EXISTS (SELECT * FROM Table)...
For a result set, SELECT TOP 1 1 FROM Table returns either zero or one rows
For exactly one row with a count (0 or non-zero), SELECT COUNT(*) FROM Table
Also, you can use exists
select case when exists (select 1 from table)
then 'contains rows'
else 'doesnt contain rows'
end
or to check if there are child rows for a particular record :
select * from Table t1
where exists(
select 1 from ChildTable t2
where t1.id = t2.parentid)
or in a procedure
if exists(select 1 from table)
begin
-- do stuff
end
Like Other said you can use something like that:
IF NOT EXISTS (SELECT 1 FROM Table)
BEGIN
--Do Something
END
ELSE
BEGIN
--Do Another Thing
END
FOR the best performance, use specific column name instead of * - for example:
SELECT TOP 1 <columnName>
FROM <tableName>
This is optimal because, instead of returning the whole list of columns, it is returning just one. That can save some time.
Also, returning just first row if there are any values, makes it even faster. Actually you got just one value as the result - if there are any rows, or no value if there is no rows.
If you use the table in distributed manner, which is most probably the case, than transporting just one value from the server to the client is much faster.
You also should choose wisely among all the columns to get data from a column which can take as less resource as possible.
Can't you just count the rows using select count(*) from table (or an indexed column instead of * if speed is important)?
If not then maybe this article can point you in the right direction.
Fast:
SELECT TOP (1) CASE
WHEN **NOT_NULL_COLUMN** IS NULL
THEN 'empty table'
ELSE 'not empty table'
END AS info
FROM **TABLE_NAME**