Check if record exists with Dapper ORM - dapper

What is the simplest way to check if record exists using the Dapper ORM?
Do I really need to define POCO objects for a query where I only want to check if a record exists?

int id = ...
var exists = conn.ExecuteScalar<bool>("select count(1) from Table where Id=#id", new {id});
should work...

I think this may have a tad less overhead as there's no function call or data type conversions:
int id = ...
var exists = connection.Query<object>(
"SELECT 1 WHERE EXISTS (SELECT 1 FROM MyTable WHERE ID = #id)", new { id })
.Any();

const string sql = "SELECT CAST(CASE WHEN EXISTS (SELECT 1 FROM MyTable WHERE Id = #Id) THEN 1 ELSE 0 END as BIT)";
bool exists = db.ExecuteScalar<bool>(sql, new { Id = 123 });

You can have your query to return a bool:
[Test]
public void TestExists()
{
var sql = #"with data as
(
select 1 as 'Id'
)
select CASE WHEN EXISTS (SELECT Id FROM data WHERE Id = 1)
THEN 1
ELSE 0
END AS result
from data ";
var result = _connection.Query<bool>(sql).FirstOrDefault();
Assert.That(result, Is.True);
}

conn.QuerySingleOrDefault<bool>("select top 1 1 from table where id=#id", new { id});

Another option that will run with duplicate records, i.e. not querying the id of the table
bool exists = connection.ExecuteScalar<int>(
"select count(1) from Table where notanId=#value", new { value = val})
> 0;

If you need to do this sort of query against a non-unique field you can use HAVING to handle counts greater than 1.
SELECT 1
FROM Table
WHERE Col=#val
HAVING COUNT(1) > 0

imho SELECT TOP(1) is better than SELECT COUNT(1)
bool exists = connection.Query<ValueTuple<long>>(
"SELECT top(1) Id FROM MYTABLE WHERE MYTABLE.Id=#Id",
new {Id}).Any());
The ValueTuple<long> is value type . Query<object> map to reference type and causes boxing .

Related

I want to generate serial Number automatically by adding plus 1 number in asp.net web api

How to take dataset and get max serial number from database generate number automatically by adding plus 1 number
var SerialNo = Convert.ToInt64(row[0]) + 1;
is this example is correct
My API
[HttpGet]
[Route("api/boq/getserialno/{id}")]
public BOQ GetBoqSerialNo(long id)
{
var result = new BOQ();
var dsBoq = SqlHelper.ExecuteDataset(AppDatabaseConnection, CommandType.StoredProcedure, 0, "GetSerialNo", new SqlParameter("#FinancialYearId", id));
if (dsBoq.Tables[0].Rows.Count > 0)
{
DataRow row = dsBoq.Tables[0].Rows[0];
var SerialNo = Convert.ToInt64(row[0]) + 1;
result = new BOQ
{
SerialNumber = Convert.ToInt64(row[0])
};
}
return result;
}
Stored procedure:
ALTER PROCEDURE [dbo].[GetSerialNo]
#FinancialYearId BIGINT
AS
BEGIN
SELECT MAX(SerialNumber) AS SerialNumber
FROM BillOfQuotation
WHERE FinancialYearId = #FinancialYearId
END
You may update your query by this:
string SQLString = "
UPDATE s SET s.SerialNumber= t.rno from BillOfQuotation as s
inner join (
select ROW_NUMBER() over (order by (select 1000)) as rno, * from
BillOfQuotation where FinancialYearId=#FinancialYearId ) as t
on s.col1=t.col1 and s.FinancialYearId=t.FinancialYearId
where s.FinancialYearId=#FinancialYearId " ----- here apply join as per the unique values in your table
Here we are generating unique row_number for each row and update it respectively as Serial No. If you have some column or id maintained for ordering then you may use that column instead of select 1000.

SQL Server Cannot Update Table with Subqueries

I'm trying to update a temporary table called #deletedRecords which looks like this:
With the data from a table called log that looks like this:
The KeyValue in the log table is the same as the ID in #deletedRecords.
There is a column in #deletedRecords for every FieldName for any particular key value.
I tried to extract the values using the following query:
UPDATE #deletedRecords
SET PatientName = (SELECT ACL.OldValue WHERE ACL.FieldName = 'CptCode'),
ChargeNotes = (SELECT ACL.OldValue WHERE ACL.FieldName = 'ChargeNotes'),
Units = (SELECT ACL.OldValue WHERE ACL.FieldName = 'Units'),
ChargeStatusID = (SELECT ACL.OldValue WHERE ACL.FieldName = 'Units')
FROM Log ACL
JOIN #deletedRecords DR ON ACL.KeyValue = DR.ID
WHERE ACL.TableName = 'BillingCharge'
AND ACL.EventType = 'DELETE'
However when I run the query all of the columns to be updated in #deletedRecords are null. Can somebody please help explain what I'm missing?
Thanks in advance.
EDIT:
In response to #Yogesh Sharma's answer, I elected to use the CTE method. I would this that using the values from the CTE to join to additional tables and extract their values during the update.
e.g. The Log table doesn't contain an old value for the StatusName but it does contain the ChargeStatusID which could be used to join to another table that contains that information such as this table ChargeStatus:
Thus I modified #Yogesh Sharma's code to the following:
WITH cte AS
...
UPDATE d
SET d.PatientName = c.PatientName
, d.StatusName = cs.StatusName
FROM #deletedBillingChargeTemp d
JOIN cte c ON c.KeyValue = d.chargeID
JOIN ChargeStatus cs ON c.ChargeStatusID = cs.ChargeStatusID
However, once I add that secondary join, all of the updated values return to null as they were before #Yogesh Sharma's suggestions were implemented.
Your query does not work because the UPDATE is executed multiple times for each row in DR, considering only the conditions specified in the last three rows of your query (not the ones specified in the subqueries). The values that remain in the table are the ones that correspond to the ACL row used in the last execution (and the order of execution cannot be controlled). If for ACL row used in the last execution the subqueries return NULL, you will get a NULL result.
See the example in the https://learn.microsoft.com/en-us/sql/t-sql/queries/update-transact-sql topic, where it says "The results of an UPDATE statement are undefined if the statement includes a FROM clause that is not specified in such a way that only one value is available for each column occurrence that is updated, that is if the UPDATE statement is not deterministic.".
You should rewrite your query like this:
UPDATE #deletedRecords
SET PatientName = (
SELECT ACL.OldValue FROM Log ACL
WHERE ACL.FieldName = 'CptCode' AND ACL.KeyValue = DR.ID
AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
),
ChargeNotes = (
SELECT ACL.OldValue FROM Log ACL
WHERE ACL.FieldName = 'ChargeNotes' AND ACL.KeyValue = DR.ID
AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
),
Units = (
SELECT ACL.OldValue FROM Log ACL
WHERE ACL.FieldName = 'Units' AND ACL.KeyValue = DR.ID
AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
),
ChargeStatusID = (
SELECT ACL.OldValue FROM Log ACL
WHERE ACL.FieldName = 'Units' AND ACL.KeyValue = DR.ID
AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
)
FROM #deletedRecords DR
You would required to do some conditional aggregation for log table and do the JOINs in order to update the temporary table #deletedRecords records
So, the conditional approach could be achieve via CTE or Subquery
WITH cte AS
(
SELECT KeyValue,
MAX(CASE WHEN FieldName = 'CptCode' THEN OldValue END) PatientName,
MAX(CASE WHEN FieldName = 'ChargeNotes' THEN OldValue END) ChargeNotes,
...
FROM Log
WHERE TableName = 'BillingCharge' AND EventType = 'DELETE'
GROUP BY KeyValue
)
UPDATE d
SET d.PatientName = c.PatientName,
...
FROM #deletedRecords d
INNER JOIN cte c ON c.KeyValue = d.ID
The other way is to update your temporary table via correlation approach
UPDATE d
SET d.PatientName = (SELECT TOP 1 OldValue FROM Log WHERE KeyValue = d.ID AND
TableName = 'BillingCharge' AND EventType = 'DELETE' AND FieldName = 'CptCode'),
d.ChargeNotes= (SELECT TOP 1 OldValue FROM Log WHERE KeyValue = d.ID AND
TableName = 'BillingCharge' AND EventType = 'DELETE' AND FieldName = 'ChargeNotes'),
...
FROM #deletedRecords d
If your updated columns are NULL, these are it's possible causes:
Since you are doing a INNER JOIN, records might not be joining correctly by their joining column. Make sure both tables have the same values on the joining columns.
Since you are filtering in a WHERE clause, records might not fulfill your TableName and EventType filters. Make sure there are records that sucessfully INNER JOIN between them and they have the supplied TableName and EventType.
The values you are asigning are NULL. Make sure your subqueries return a not null value.
Table reference is off. When updating a table in SQL Server, always use the updating table alias if you are using one.
Use
UPDATE DR SET
YourColumn = Value
FROM
Log ACL
JOIN #deletedRecords DR ON -...
Instead of
UPDATE #deletedRecords SET
YourColumn = Value
FROM
Log ACL
JOIN #deletedRecords DR ON -...
Make sure you are NOT checking the variable table values on another batch, script or procedure. Variable tables scope are limited to current batch or procedure, while temporary tables remain as long as the session is alive.
Make sure that there isn't another statement that is setting those values as NULL after your update. Also keep an eye on your transactions (might not be commited or rolled back).

join oracle database table with table of custom type

I want to join a table say EMPLOYEE with another custom oracle type MATCHING_CRITERIA_LIST.
MATCHING_CRITERIA_LIST is a table of a custom oracle type CRITERIA. All DDL as follows:
CREATE OR REPLACE
type CRITERIA as object (
DOB DATETIME,
SALARY NUMBER
);
CREATE OR REPLACE TYPE
MATCHING_CRITERIA_LIST IS TABLE OF CRITERIA;
CREATE TABLE EMPLOYEE{
ID NUMBER PRIMARY KEY NOT NULL,
NAME VARCHAR(20 BYTE),
DOB DATETIME,
SALARY NUMBER
}
What I am actually trying to achieve is,
var allEmployeeList = new List<Employee>();
var filteredList = new List<Employee>();
var matchingCriteria = new List<MatchingCritera>{
new MatchingCritera(){DOB = <date1>, salary = <sal1>},
new MatchingCritera(){DOB = <date2>, salary = <sal2>},
new MatchingCritera(){DOB = <date3>, salary = <sal1>}
}
foreach(var emp in allEmployeeList)
{
foreach(var criteria in matchingCriteria)
{
if(emp.DOB == criteria.DOB && emp.salary = criteria.salary)
{
filteredList.Add(emp);
}
}
}
I want this same logic to be in SP. I am currently doing as follows which is working fine.
CREATE OR REPLACE
type IDTYPE as object (
id NUMBER
);
CREATE OR REPLACE
type IDTABLETYPE IS TABLE OF IDTYPE;
CREATE OR REPLACE PROCEDURE GET_FILTERED_EMPLOYEE (
IN_CRITERIA_LIST IN MATCHING_CRITERIA_LIST,
CUR_OUT OUT sys_refcursor
)
IS
V_ID_TABLE IDTABLETYPE;
V_TEMP_ID_COLL EMPLOYEE_ID;
BEGIN
V_ID_TABLE := IDTABLETYPE();
V_TEMP_ID_COLL := EMPLOYEE_ID();
IF IN_CRITERIA_LIST.COUNT > 0 THEN
FOR i IN IN_CRITERIA_LIST.FIRST .. IN_CRITERIA_LIST.LAST
LOOP
SELECT EMP.ID BULK COLLECT INTO V_TEMP_ID_COLL FROM EMPLOYEE EMP WHERE
EMP.DOB = IN_CRITERIA_LIST(i).DOB
AND EMP.SALARY = IN_CRITERIA_LIST(i).SALARY
ORDER BY EMP.ID DESC;
IF (V_TEMP_ID_COLL.COUNT > 0) THEN
FOR j IN V_TEMP_ID_COLL.FIRST .. V_TEMP_ID_COLL.LAST
LOOP
V_ID_TABLE.extend();
V_ID_TABLE(V_ID_TABLE.count) := IDTYPE(TO_NUMBER(V_TEMP_ID_COLL(j)));
END LOOP;
END IF;
END LOOP;
END IF;
OPEN CUR_OUT FOR
SELECT * FROM EMPLOYEE EMP WHERE EMP.ID IN (SELECT * FROM TABLE(V_ID_TABLE));
END;
I want to remove the for loop on IN_CRITERIA_LIST, as it is impacting the performance, and do something like below:
SELECT * FROM EMPLOYEE EMP
INNER JOIN MATCHING_CRITERIA_LIST MCL ON
EMP.DOB = MCL.DOB
AND EMP.SALARY = MCL.SALARY
ORDER BY TD.TRANS_DASHBOARD_ID DESC;
Can someone guide how I can join my custom table of UDT with and oracle table?
You do not need an IDTYPE object or all the PL/SQL loops (or even joins):
CREATE OR REPLACE PROCEDURE GET_FILTERED_EMPLOYEE (
IN_CRITERIA_LIST IN MATCHING_CRITERIA_LIST,
CUR_OUT OUT sys_refcursor
)
IS
BEGIN
OPEN CUR_OUT FOR
SELECT *
FROM EMPLOYEE
WHERE CRITERIA( dob, salary ) MEMBER OF IN_CRITERIA_LIST;
END;
/
This worked for me. Thanks.
SELECT * FROM EMPLOYEE EMP
INNER JOIN TABLE(IN_CRITERIA_LIST) MCL ON
EMP.DOB = MCL.DOB
AND EMP.SALARY = MCL.SALARY
ORDER BY TD.TRANS_DASHBOARD_ID DESC;

SQL not exists returning query values

I'm having some trouble with a query to check differences between 2 identical tables with different rows.
This is the query
SELECT *
FROM [PROD01].[myDefDB].[forward].[fv] as DB01
WHERE TargetDate = '20150429' and
NOT EXISTS (SELECT *
FROM [PROD02].[myDefDB].[forward].[fv] as DB02
WHERE DB02.TargetDate = '20150429' and
DB02.Id_Fw = DB01.Id_Fw and
DB02.Id_Bl = DB01.Id_Bl and
DB02.Id_Pt = DB01.Id_Pt and
DB02.TargetDate = DB01.TargetDate and
DB02.StartDate = DB01.EndDate and
DB02.EndDate = DB01.EndDate and
DB02.[Version] = DB01.[Version]
)
Consider that [PROD02].[myDefDB].[forward].[fv] is a subset of [PROD01].[myDefDB].[forward].[fv], that performing a SELECT count(*) on both tables for the TargetDate = '20150429' returns me 2367 and 4103, so I expect to get 1736 from that query but I get more than 2000.
I considered all PKs in the WHERE clause. What am I missing?
You can use EXCEPT like this.
SELECT Id_Fw,Id_Bland,Id_Pt,TargetDate,StartDate,EndDate,[Version]
FROM [PROD01].[myDefDB].[forward].[fv] as DB01
WHERE TargetDate = '20150429'
EXCEPT
SELECT Id_Fw,Id_Bl,Id_Pt,TargetDate,StartDate,EndDate,[Version]
FROM [PROD02].[myDefDB].[forward].[fv] as DB02
WHERE TargetDate = '20150429'
This will get you all the rows in PROD01 which are not in PROD02

Passing values from One SQL Query to another and use the IF Statement to determine the result

I am trying to do something I have never done before. I have the following SQL Queries:
SELECT a.UserID, u.Initials, u.Surname, u.Email, u.CountryID
FROM [dbo].[App] a
INNER JOIN [dbo].[User] u ON a.UserID = u.ID
WHERE a.ID = 46451
This query return the following information:
UserID: 51637
Initials: T
Surname: Tester
Email: petercash#live.co.za
CountryID: 203
Now I would like to take the CountryID returned which is 203 and check if it exists in the sadc table and if it does, then use it to retrieve data from the cost table
IF ((SELECT COUNT(*) AS counted FROM [dbo].[Sadc] WHERE CountryID = 203) > 0)
SELECT Cost FROM [dbo].[Cost] WHERE ID = 4
The a.ID (In the WHERE clause) in the first SQL Query to be a parameter(as the value will change every time).
Then take the value of the CountryID and pass it to the second query and return the cost from the Cost table
You pretty much typed in the best way to do this in your question.
SELECT Cost
FROM [dbo].[Cost]
WHERE ID = 4
AND EXISTS (SELECT * FROM [dbo].[Sadc] WHERE CountryID = 203)
You can set up a variable to hold the value and use an EXISTS statement to check if it is in the table:
-- variable to hold the value
DECLARE #CountryId INT
-- this set's the value of #CountryId
SELECT #CountryId = u.CountryID
FROM [dbo].[App] a
INNER JOIN [dbo].[User] u ON a.UserID = u.ID
WHERE a.ID = 46451
-- check if it exists in [Sadc]
IF EXISTS(SELECT 1 FROM [dbo].[Sadc] WHERE CountryID = #CountryId)
BEGIN
-- run your code if it exists
SELECT Cost FROM [dbo].[Cost] WHERE ID = 4
END

Resources