Check if value exists in multiple tables - c#

I have such tables in my database like Customer, Member, Instructor, Employee etc. Each of these users has his email adrress. I need to check if there is already a user with given email. I was thinking about:
Check each table, something like this:
public bool IsEmailAddressExists(string email)
{
if (!Context.Customers.Any(c => string.Equals(c.Email, email, StringComparison.InvariantCultureIgnoreCase)))
if (!Context.Members.Any(m => string.Equals(m.Email, email, StringComparison.InvariantCultureIgnoreCase)))
...
}
Select all emails and check:
public bool IsEmailAddressExists(string email)
{
var emails = Context.Customers.Select(c => c.Email).Union(Context.Members.Select(m => m.Email))...; //other unions
return emails.Any(e => string.Equals(e, email, StringComparison.InvariantCultureIgnoreCase));
}
There are more tables and many users, so I would like to know what would be the most efficient way to implement such kind of checking.
Thank you.

It sounds like you have a couple of options.
Create a view. You could create a view in the database that shows, say, email addresses only. Assuming you're using MSSQL Server, something like:
CREATE VIEW EmailView AS
SELECT Email from Customers
UNION ALL
SELECT Email from Instructors
....
... then using an entity bound to that view so you can check the list of emails to see if that email exists already. Check out the documentation for more information.
Normalize your database. Do each of these tables share common information beyond email, say, first name and/or last name? It might be worth your time to reorganize your data model to put that information in a "Persons" table, then foreign key your other tables to it. (This will also help if your users are two different things, say, a customer and an instructor.)

In pure SQL this would be your most efficient because it stops searching as soon as it hits a match:
... As a stored procedure:
CREATE PROCEDURE EmailExists
#email varchar(254) = NULL
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #emailExists bit
SET #emailExists = 0
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Customer WHERE email = #email)
IF #emailExists = 0
BEGIN
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Member WHERE email = #email)
IF #emailExists = 0
BEGIN
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Instructor WHERE email = #email)
IF #emailExists = 0
BEGIN
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Employee WHERE email = #email)
END
END
END
SELECT #emailExists
END
... As a scalar-valued function:
CREATE FUNCTION EmailExists
(
#email varchar(254)
)
RETURNS bit
AS
BEGIN
DECLARE #emailExists bit
SET #emailExists = 0
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Customer WHERE email = #email)
IF #emailExists = 0
BEGIN
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Member WHERE email = #email)
IF #emailExists = 0
BEGIN
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Instructor WHERE email = #email)
IF #emailExists = 0
BEGIN
SELECT #emailExists = 1 WHERE EXISTS(SELECT 1 FROM Employee WHERE email = #email)
END
END
END
-- Return the result of the function
RETURN #emailExists
END
In C# with Linq, you can use the Any extension and the || operator. Since Any usually gets translated to EXISTS in SQL and evalutation of the || operator in C# is lazy, evaluation will stop as soon as the first ocurrence of an email is reached.
bool emailExists = customerEmails.Any(e => string.Equals(e, email, StringComparison.InvariantCultureIgnoreCase))
|| memberEmails.Any(e => string.Equals(e, email, StringComparison.InvariantCultureIgnoreCase))
|| instructorEmails.Any(e => string.Equals(e, email, StringComparison.InvariantCultureIgnoreCase))
|| employeeEmails.Any(e => string.Equals(e, email, StringComparison.InvariantCultureIgnoreCase));

Related

Stored Procedure changing where clause statements

I have a question regarding sql statements. Is it possible to make a query this way? I need to filter a where clause that depends what is the value of #user_id.
ALTER PROCEDURE [dbo].[getUserAddress]
#user_id int = null
AS
SELECT user_id, state_code, address from UserAddress
IF(#user_id > 10)
BEGIN
WHERE state_code = 'CA'
END
ELSE
WHERE address = 'HILLS'
END
I tried to do this way but It seems not a standard way.
IF(#user_id > 10)
BEGIN
SELECT user_id, state_code, address from UserAddress WHERE state_code = 'CA'
END
ELSE
SELECT user_id, state_code, address from UserAddress WHERE address = 'HILLS'
END
Please advise what is the best approach for this concept. Please help.
Thanks
You are missing a begin after your else. Try this:
IF(#user_id > 10)
BEGIN
SELECT user_id, state_code, address from UserAddress WHERE state_code = 'CA'
END
ELSE
BEGIN
SELECT user_id, state_code, address from UserAddress WHERE address = 'HILLS'
END
You can simplify:
select
user_id,
state_code,
address
from
UserAddress
where
(#user_id > 10 and state_code = 'CA') or
(#user_id IS NULL OR (#user_id <= 10 and address = 'HILLS'))
If you will add more filter criteria in the future you should be aware of parameter sniffing.
As an aside, creating an index on (user_id, state_code, address) will be a covering index for this query.
You can also use a dynamic sql query in the stored procedure.
Query
declare #sql as varchar(max);
select #sql = 'select * from [UserAddress] '
+ stuff((select case when #user_d > 10
then 'where state_code= ''CA'''
else 'where address = ''Hills''' end
for xml path('')), 1,0,'')
exec(#sql);
rather then this use can use case in your where statement:
SELECT user_id, state_code, address from UserAddress WHERE
(case when #user_id > 10 then state_code else address end)
= (case when #user_id > 10 then 'CA' else 'HILLS' end)
Try this
SELECT user_id, state_code, address from UserAddress
WHERE
((WHERE state_code = 'CA') AND (#user_id > 10))
OR
((WHERE address = 'HILLS') AND (#user_id <= 10))
You can simply...
WHERE
(#user_id > 10 AND state_code = 'CA')
OR ((#user_id <= 10 OR #user_id IS NULL) AND address = 'HILLS')
However, this approach may not produce the best query plan. If that turns out to be a problem, either use separate queries (as you already tried, but fix the syntax error as suggested by AsheraH), or dynamic SQL.
BTW, you can write separate queries more succinctly like this:
IF #user_id > 10
SELECT user_id, state_code, address from UserAddress WHERE state_code = 'CA'
ELSE
SELECT user_id, state_code, address from UserAddress WHERE address = 'HILLS'
You can try this:
ALTER PROCEDURE [dbo].[getUserAddress]
#user_id int = null
AS
BEGIN
Declare #sql nvarchar(5000)
set #sql='SELECT user_id, state_code, address from UserAddress'
IF(#user_id > 10)
BEGIN
set #sql=#sql+' WHERE state_code = ''CA'''
END
ELSE
set #sql=#sql+' WHERE address = ''HILLS'''
END
Exec(#sql)
END

Retrieve multiple data from stored procedure using Linq-to-SQL

I am using Silverlight and Linq-to-SQL to communicate with the database.
I have a stored procedure which receives 2 parameters (PFOID and Quantity) and Userid and returns a product name.
If we send multiple values like multiple pfoid's and quantity's it will return multiple product names shown as below
The stored procedure looks like this..
ALTER PROCEDURE [PFO].[PFOValidateUpdateData]
#PfoIDs xml, -- list of PFO ID's
#UserID uniqueidentifier --The Identity of the User making the call.
AS
BEGIN
-- SET DEFAULT BEHAVIOR
SET NOCOUNT ON -- Performance: stops rows affected messages
SET DEADLOCK_PRIORITY LOW -- This SP to be the Deadlock victim
-- Initialise Lock-Timeout and Deadlock vars for Insert
DECLARE #iLockTimeoutRetries as int
DECLARE #iDeadLockRetries as int
DECLARE #dtLockTimeoutSleepInterval as datetime
DECLARE #dtDeadlockSleepInterval as datetime
DECLARE #iErrorNumber as int
SET #iLockTimeoutRetries = 0
SET #iDeadLockRetries = 0
SET #dtLockTimeoutSleepInterval = sCommon.fnLockTimeoutSleepInterval()
SET #dtDeadlockSleepInterval= sCommon.fnDeadlockSleepInterval()
SET #iErrorNumber = 0
-- procedure specific
DECLARE #idoc as int
DECLARE #IsBrightstarUser as bit
RETRY:
BEGIN TRY
--Create Temp table to store stores!
CREATE TABLE [#PFOList]
(
[PFOId] nvarchar(50),
[Quantity] INT
)
--Create Temp table to store User stores!
CREATE TABLE [#UserStoreList]
(
[StoreID_XRef] nvarchar(50)
)
print CONVERT(varchar(1000), #PfoIDs)
--Create Document
EXEC sp_xml_preparedocument #idoc OUTPUT, #PfoIDs
-- Append to new list of Store records
INSERT INTO [#PFOList] (
[PFOId],
[Quantity]
)
SELECT [PFOID],[Quantity]
FROM OPENXML (#idoc, 'ArrayOfString/string',2)
WITH( [PFOID] nvarchar(50),[Quantity] [INT]) Stores
--WHERE [PFOId] Is Not NULL
-- Clean UP
exec sp_xml_removedocument #iDoc
-- are we dealing with a brightstar user?
SET #IsBrightstarUser = CASE WHEN exists
(SELECT *
FROM dbo.aspnet_UsersInRoles AS uir inner join
dbo.aspnet_Roles AS roles ON uir.RoleId = roles.roleid
WHERE roles.rolename = 'Brightstar Employee' and uir.userid = #userid)
THEN 1 ELSE 0 END
--Get User Storelist
INSERT INTO [#UserStoreList] (
[StoreID_XRef]
)
SELECT s.StoreId_XRef
FROM PFO.UserStoreLink us(nolock)
INNER JOIN PFO.Store s(nolock)
ON us.StoreId=s.StoreId
where UserId=#UserID
--Select * from [#PFOList]
--SELECT #IsBrightstarUser AS ISBrightstaruser
--SELECT * from [#UserStoreList]
--If BrightstarCustomer Update all the Quantities.
IF #IsBrightstarUser=1
BEGIN
UPDATE
PFO.PFO
SET
IsBrightstarReviewComplete = 1
,[ModifyingUsersID] = #UserID
,[ModifiedDate] = getdate()
,[PlannedQty] = pfol.[Quantity]
,[BrightstarReviewedQty]=pfol.[Quantity]
FROM
PFO.PFO as pfo
INNER JOIN [#UserStoreList] as stores on pfo.StoreId_XRef=stores.StoreID_XRef
INNER JOIN [#PFOList] as pfol on pfo.PFOId = pfol.PFOId
WHERE #IsBrightstarUser = 1
END
ELSE BEGIN
--Update Non Contrained Orders
UPDATE
PFO.PFO
SET
[ModifyingUsersID] = #UserID
,[ModifiedDate] = getdate()
,[PlannedQty] = pfol.[Quantity]
FROM
PFO.PFO (nolock) as pfo
INNER JOIN [#UserStoreList] as stores on pfo.StoreId_XRef=stores.StoreID_XRef
INNER JOIN [#PFOList] as pfol on pfo.PFOId = pfol.PFOId
WHERE pfo.IsBrightstarReviewComplete=1 AND IsConstraint=0
--SELECT * from PFO.PFO (nolock) where PFOId='04676723-2afb-49ff-9fa1-0131cabb407c'
--Update Contrained Orders
--Get Existing quantities for the User
CREATE TABLE #ExistingProductQuantity
(
[PfoID] nvarchar(100)
,[Product] nvarchar(255)
,[PlannedQty] INT
,[BrightstarReviewedQty] INT
)
CREATE TABLE #CustProductQuantity
(
[Product] nvarchar(255)
,[IsUpdatable] BIT
)
INSERT INTO #ExistingProductQuantity
( [PfoID],[Product],[PlannedQty],[BrightstarReviewedQty])
SELECT PFOId,InventoryId,PlannedQty,BrightstarReviewedQty
FROM PFO.PFO as pfo
INNER JOIN [#UserStoreList] as stores on pfo.StoreId_XRef=stores.StoreID_XRef
WHERE pfo.IsBrightstarReviewComplete=1 AND IsConstraint=1
UPDATE
#ExistingProductQuantity
SET [PlannedQty]=pfol.[Quantity]
FROM #ExistingProductQuantity eoq
INNER JOIN [#PFOList] as pfol on eoq.PFOId = pfol.PFOId
INSERT INTO #CustProductQuantity
( [Product],[IsUpdatable] )
SELECT
[Product],
CASE WHEN SUM(PlannedQty)<=SUM(BrightstarReviewedQty) THEN 1 ELSE 0 END
FROM #ExistingProductQuantity
GROUP BY [Product]
--SELECT * from #ExistingProductQuantity
--SELECT * from #CustProductQuantity
--Update the products that can be updatable
UPDATE
PFO.PFO
SET
[ModifyingUsersID] = #UserID
,[ModifiedDate] = getdate()
,[PlannedQty] = pfol.[Quantity]
FROM
PFO.PFO as pfo
INNER JOIN #UserStoreList as stores on pfo.StoreId_XRef=stores.StoreID_XRef
INNER JOIN #PFOList as pfol on pfo.PFOId = pfol.PFOId
INNER JOIN #CustProductQuantity as pr on pr.Product=pfo.InventoryId
WHERE pfo.IsBrightstarReviewComplete=1 AND pr.IsUpdatable=1 AND IsConstraint=1
--Return the products that are not updatabele
select [Product]
FROM #CustProductQuantity
where [IsUpdatable]=0
END
END TRY
BEGIN CATCH
-- Get the ErrorNumber
Set #iErrorNumber = ERROR_NUMBER()
--Handle Deadlock situation (Deletes, Inserts & Updates)
IF #iErrorNumber = 1205
BEGIN
-- If we have not made enough attempts to break the lock
IF #iDeadLockRetries < sCommon.fnMaxDeadlockRetries()
BEGIN
-- Increment the Attempt count
SET #iDeadLockRetries = #iDeadLockRetries + 1
-- Pause to allow the deadlock contention to clear
WAITFOR DELAY #dtDeadlockSleepInterval
GOTO RETRY
END
END
-- Handle Lock Timeout situation (Deletes, Inserts & Updates)
IF #iErrorNumber = 1222
BEGIN
-- If we have not made enough attempts to break the Deadlock
IF #iLockTimeoutRetries < sCommon.fnMaxLockTimeoutRetries()
BEGIN
-- Increment the Attempt count
SET #iLockTimeoutRetries = #iLockTimeoutRetries + 1
-- Pause to allow the lock contention to clear
WAITFOR DELAY #dtLockTimeoutSleepInterval
GOTO RETRY
END
END
exec Common.RethrowError
END CATCH
END
The result is as follows..
Product
6435LVWK-360-CD819E3
NSCHI535C1097I360-4C
NSCHU485C1819I360-0C
Return Value
0
My Linq-to-SQL connection is like this
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="PFO.PFOValidateUpdateData")]
public int PFOValidateUpdateData([global::System.Data.Linq.Mapping.ParameterAttribute(Name = "PfoIDs", DbType = "Xml")] System.Xml.Linq.XElement pfoIDs, [global::System.Data.Linq.Mapping.ParameterAttribute(Name = "UserID", DbType = "UniqueIdentifier")] System.Nullable<System.Guid> userID)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), pfoIDs, userID);
return ((int)(result.ReturnValue));
}
I am trying to retrieve all the data from the stored procedure but the when I debugging it the return value is "o"..
I would be grateful to you if you could help me retrieve all the data returned by the stored procedure... thank you very much...
If your stored procedure returns a collection of nvarchar's, then the signature of your Linq2Sql method is not correct. It should not return an int, but an ISingleResult.
So the correct signature will be:
public ISingleResult<string> PFOValidateUpdateData(...)
{
IExecuteResult result = this....;
return (ISingleResult<string>)result.ReturnValue;
}
var products = PFOValidateUpdateData(...).ToList();
If you want to return the results from multiple SELECT's in your stored procedure, you'll have to use IMultipleResults.
Well I know this is not the right way...for time being,its working for me...
I created an other table with two columns one ProductId and ID, I am inserting the values returned by the stored procedure,
in the designer.cs I am returning the table,
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="PFO.PFOValidateUpdateData")]
public ISingleResult<PFOValidData> PFOValidateUpdateData([global::System.Data.Linq.Mapping.ParameterAttribute(Name = "PfoIDs", DbType = "Xml")] System.Xml.Linq.XElement pfoIDs, [global::System.Data.Linq.Mapping.ParameterAttribute(Name = "UserID", DbType = "UniqueIdentifier")] System.Nullable<System.Guid> userID)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), pfoIDs, userID);
return ((ISingleResult<PFOValidData>)(result.ReturnValue));
}
And in the Domainservice
List<string> PFOValidateUpdateData(string pfoIds, Guid userID)
{
List<string> productIdList = new List<string>();
// Acquire the int
result = this.DataContext.PFOValidateUpdateData(element, userID);
foreach (var item in result)
{
productIdList.Add(item.ProductID);
}
return productIdList;
To get the multiple values returned by the stored procedure....
Please let me know if there is a better way to solve this... thank you

Dynamic SQL Server Query to Fill DataTable

Hello I need to do the follow query in SQL Server to fill and Datatable.
In my case I have 3 tables:
1 - Users
2 - Process
3 - Status
Users
id, name
Process
id, cod_user, cod_status
Status
id, status
I need to make an query that return the follow table:
User.Name | Status.Created | Status.Opened | Status.Finalized
Tom 50 30 20
Roger 22 33 44
Kris 11 09 05
And then, I have to return this table to fill and datatable.
Thanks...
Looks like you are trying to PIVOT the data, you can use something like this if you know the values of status to transform:
select name, [Created], [Opened], [Finalized]
from
(
select u.name,
s.status
from users u
left join process p
on u.id = p.cod_user
left join status s
on p.cod_status = s.id
) src
pivot
(
count(status)
for status in ([Created], [Opened], [Finalized])
) piv
If you have an unknown number of statuses to turn into columns, then you can use dynamic sql:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(status)
from status
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT name, ' + #cols + ' from
(
select u.name,
s.status
from users u
left join process p
on u.id = p.cod_user
left join status s
on p.cod_status = s.id
) x
pivot
(
count(status)
for status in (' + #cols + ')
) p '
execute(#query)
If you don't have access to the PIVOT function, then you can replicate it using an aggregate function and a CASE statement:
select u.name,
sum(case when s.status = 'created' then 1 else 0 end) created,
sum(case when s.status = 'opened' then 1 else 0 end) opened,
sum(case when s.status = 'finalized' then 1 else 0 end) finalized
from users u
left join process p
on u.id = p.cod_user
left join status s
on p.cod_status = s.id
group by u.name
Looks like you're trying to show one record per User, with one column per Status, and the columns contain the count of records in the Process table with that status for that user?
If that's correct, then you want to use a Pivot Table.

Parameters to the EXISTS clause in a stored procedure

I have a table DEPT, which holds 2 columns - ID, NAME.
A search form is presented with the IDs from the DEPT table and the user can chose any number of IDs and submit the form, to get the related NAMEs.
Clarification/Inputs:
I don't want to build a dynamic query - its not manageable.
I prefer a stored procedure using table-valued parameters
Any other solutions to proceed?
NOTE:
This example is simple with 1 table - in real life, I have to deal with more than 6 tables!
Thanks for any suggestions
CREATE TYPE dbo.DeptList
AS TABLE
(
ID INT
);
GO
CREATE PROCEDURE dbo.RetrieveDepartments
#dept_list AS dbo.DeptList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT Name FROM dbo.table1 WHERE ID IN (SELECT ID FROM #dept)
UNION ALL
SELECT Name FROM dbo.table2 WHERE ID IN (SELECT ID FROM #dept)
-- ...
END
GO
Now in your C# code, create a DataTable, fill it in with the IDs, and pass it in to the stored procedure. Assuming you already have a list called tempList and the IDs are stored in id:
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID"));
foreach(var item in tempList)
{
tvp.Rows.Add(item.id);
}
using (connObject)
{
SqlCommand cmd = new SqlCommand("StoredProcedure", connObject);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#dept_list", tvp);
tvparam.SqlDbType = SqlDbType.Structured;
...
}
You can also use a split function. Many exist, this is the one I like if you can guarantee that the input is safe (no <, >, & etc.):
CREATE FUNCTION dbo.SplitInts_XML
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'int')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a
CROSS APPLY x.nodes('i') AS y(i)
);
GO
Now your procedure can be:
CREATE PROCEDURE dbo.RetrieveDepartments
#dept_list VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
;WITH d AS (SELECT ID = Item FROM dbo.SplitInts(#dept_list, ','))
SELECT Name FROM dbo.table1 WHERE ID IN (SELECT ID FROM d)
UNION ALL
SELECT Name FROM dbo.table2 WHERE ID IN (SELECT ID FROM d)
-- ...
END
GO

SQL Server: Check if Child Rows Exist

I am working on a web application where there are many tables but two will suffice to illustrate my problem:
User
Order
Let us say that the User table has a primary key "UserID", which is a foreign key in the Order table called "CreatedBy_UserID".
Before deleting a User, I would like to check if the Order table has a record created by the soon-to-be deleted user.
I know that a SqlException occurs if I try to delete the user but let us say that I want to check beforehand that the Order table does not have any records created by this user? Is there any SQL code which I could run which will check all foreign keys of a table if that row is being referenced?
This for me is generally useful code as I could remove the option for deletion altogether if it can be detected that the user exists in these other tables.
I don't want a simple query (SELECT COUNT(*) FROM Order WHERE CreatedBy_UserID == #userID) because this will not work if I create another foreign key to the Order table. Instead I want something that will traverse all foreign keys.
Can this be done?
Below is code for an sp that I've used in the past to perform this task (please excuse the indenting):
create proc dbo.usp_ForeignKeyCheck(
#tableName varchar(100),
#columnName varchar(100),
#idValue int
) as begin
set nocount on
declare fksCursor cursor fast_forward for
select tc.table_name, ccu.column_name
from
information_schema.table_constraints tc join
information_schema.constraint_column_usage ccu on tc.constraint_name = ccu.constraint_name join
information_schema.referential_constraints rc on tc.constraint_name = rc.constraint_name join
information_schema.table_constraints tc2 on rc.unique_constraint_name = tc2.constraint_name join
information_schema.constraint_column_usage ccu2 on tc2.constraint_name = ccu2.constraint_name
where tc.constraint_type = 'Foreign Key' and tc2.table_name = #tableName and ccu2.column_name = #columnName
order by tc.table_name
declare
#fkTableName varchar(100),
#fkColumnName varchar(100),
#fkFound bit,
#params nvarchar(100),
#sql nvarchar(500)
open fksCursor
fetch next from fksCursor
into #fkTableName, #fkColumnName
set #fkFound = 0
set #params=N'#fkFound bit output'
while ##fetch_status = 0 and coalesce(#fkFound,0) <> 1 begin
select #sql = 'set #fkFound = (select top 1 1 from [' + #fkTableName + '] where [' + #fkColumnName + '] = ' + cast(#idValue as varchar(10)) + ')'
print #sql
exec sp_executesql #sql,#params,#fkFound output
fetch next from fksCursor
into #fkTableName, #fkColumnName
end
close fksCursor
deallocate fksCursor
select coalesce(#fkFound,0)
return 0
end
This will select a value of 1 if a row has any foreign key references.
The call you would need would be:
exec usp_ForeignKeyCheck('User','UserID',23)
There is no clean way to iterate through all FK columns where multiple exist. You'd have to build some dynamic SQL to query the system tables and test each in turn.
Personally, I wouldn't do this. I know what FKs I have: I'll test each in turn
...
IF EXISTS (SELECT * FROM Order WHERE CreatedBy_UserID == #userID)
RAISERROR ('User created Orders ', 16, 1)
IF EXISTS (SELECT * FROM Order WHERE PackedBy_UserID == #userID)
RAISERROR ('User packed Orders', 16, 1)
...
You wouldn't dynamically iterate through each property of some user object and generically test each one would you? You'd have code for each property
This code will give you a list of the foreign keys which are defined for a specifit table:
select distinct name from sys.objects
where object_id in ( select constraint_object_id from sys.foreign_key_columns as fk
where fk.Parent_object_id = (select object_id from sys.tables
where name = 'tablename') )
You can use transaction to check it.
I know it seems like stone ax, but it working fast and stable.
private bool TestUser(string connectionString, int userID)
{
var result = true;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
var command = connection.CreateCommand();
var transaction = connection.BeginTransaction();
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText = "DELETE User WHERE UserID = " + userID.ToString();
command.ExecuteNonQuery();
transaction.Rollback();
}
catch
{
result = false;
}
}
return result;
}

Categories