How can I generate a sequence number in a empty table - sql

I am trying to make a query that can generate the latest sequence number +1 to the new record in sql server.
let ignore the insert part first, I write a query like this:
SELECT 'asdf' AS col1, CASE WHEN EXISTS (SELECT pk_sales_inv_no FROM salesInvoice WHERE pk_sales_inv_no LIKE 'Q-ARF2206-%') THEN 1 ELSE 0 END AS EXPR1
It looks fine, when the record with same prefix exists, It return 1, else 0.
Because I have to process the current latest sequence number in the true value part, so I change my query with this to get the pk_sales_inv_no for the true part processing.
SELECT TOP (1) 'asdf' AS col1, CASE WHEN EXISTS (SELECT pk_sales_inv_no FROM salesInvoice WHERE pk_sales_inv_no LIKE 'Q-ARF2206-%') THEN 1 ELSE 0 END AS EXPR1 FROM salesInvoice WHERE (pk_sales_inv_no LIKE 'Q-ARF2206-%') ORDER BY pk_sales_inv_no DESC
Then problem happens, because the select result is totally empty, so It doesn't return the 1 or 0.
How can I improve it to work out with a empty select result.

You can write a simple scalar udf, if you need it in JOIN adapt it as a table value function.
I doubt that this is what you need, I think you want to get the number after the 2nd dash
IF OBJECT_ID (N'dbo.udf_lastSequence') IS NOT NULL
DROP FUNCTION dbo.udf_lastSequence
GO
CREATE FUNCTION dbo.udf_lastSequence (#invNo varchar(100))
RETURNS int
AS
BEGIN
DECLARE #lastInvNo VARCHAR(100)
DECLARE #search VARCHAR(100)
DECLARE #result int
SET #result = 0
SET #search = CONCAT(#invNo, '%');
SELECT TOP 1 #lastInvNo = pk_sales_inv_no
FROM salesInvoice
WHERE (pk_sales_inv_no LIKE #search)
ORDER BY pk_sales_inv_no DESC
IF #lastInvNo IS NOT NULL
SET #result = CAST(REPLACE(#lastInvNo, #invNo, '') AS INT);
return #result
END
GO
Try it with SELECT dbo.udf_lastSequence('Q-ARF2206-') WITHOUT the final % charter

Related

How to write if exist statement that would run a different select depending if it exists or not

I am trying to convert a sql if exists statement into a SSRS valid format to run a report on CRM.
CRM report doesn't accept the report on upload if I have a if exists method, I'm having troubles figuring out what I can use in its place.
IF EXISTS(select * from dbo.FC where dbo.FC.ContactID in (select dbo.AV.so_contactid from dbo.AV))
begin
select [STATEMENT 1]
from dbo.AV CRMAF_so_AV join
dbo.FC c
on CRMAF_so_AV.so_contactid = c.ContactID;
end
else
begin
select [STATEMENT 2]
from dbo.AV CRMAF_so_AV join
dbo.FA c
on CRMAF_so_AV.so_contactid = c.AccountID;
end;
I want to be able to either run the select [STATEMENT 1] if the condition is true else I want to run select [STATEMENT 2]
I have managed to get this to work by doing a LEFT JOIN instead of a JOIN.
select [STATEMENT 1 + 2 all columns needed]
from dbo.AV CRMAF_so_AV
left join dbo.FC c on CRMAF_so_AV.so_contactid = c.ContactID;
left join dbo.FA a on CRMAF_so_AV.so_contactid = a.AccountID;
This now runs if its an account or a contact.
Try this -
You have to put your entire statement in #select1 and #select1.
declare #statement1 as varchar(max);
declare #statement2 as varchar(max);
SET #statement1 = 'SELECT 1'
SET #statement2 = 'SELECT 2'
IF EXISTS(select * from dbo.FC where dbo.FC.ContactID in (select dbo.AV.so_contactid from dbo.AV))
BEGIN
EXEC (#statement1)
END
ELSE
BEGIN
EXEC (#statement2)
END
Instead of using if exists can you not get a count of records that meet the criteria and then if its 1 or greater run a different query as apposed to if it was equal to 0.
let me know if I am missing something what you are trying to achieve.
sorry i am unable to put comments due to having a new account so my reputation is low.
I think you need something like this:
WITH PreSelection AS (
SELECT
AV.ID AS AVID,
(SELECT TOP(1) c.ContactID FROM dbo.FC c WHERE c.ContactID = AV.so_contactid) AS ContactID,
(SELECT TOP(1) c.ContactID FROM dbo.FA c WHERE c.AccountID = AV.so_contactid) AS AccountID
FROM dbo.AV
)
SELECT
AVID,
ISNULL(
CASE WHEN ContactID IS NULL
THEN (SELECT TOP(1) AccountName FROM dbo.FA WHERE FA.AccountID = AccountID)
ELSE (SELECT TOP(1) LTRIM(RTRIM(ISNULL(FirstName, '') + ' ' + ISNULL(LastName, ''))) FROM dbo.FC WHERE FC.ContactID = ContactID)
END, '') AS ContactName
FROM PreSelection
A few things to note:
When SSRS evaluates query it expects the resluts to always have the same structure in terms of column names and types.
So you CANNOT do something like this..
IF #x=#y
BEGIN
SELECT Name, Age FROM employees
END
ELSE
BEGIN
SELECT DeptID, DeptName, DeptEMpCOunt FROM departments
END
... as this will return different types and column names and column counts.
What you CAN DO is this..
DECLARE #t TABLE(resultType int, colA varchar(128), colB int, colC varchar(128), colD int)
IF #x=#y
BEGIN
INSERT INTO #t(resultType, colA, ColB)
SELECT 1 as resultType, Name, Age FROM employees
END
ELSE
BEGIN
INSERT INTO #t(resultType, colB, colC, colD)
SELECT 2 AS resultType, DeptID, DeptName, DeptEmpCount FROM departments
END
SELECT * FROM #t
Al we are doing is creating a table that can handle all variations of the data and putting the results into whatever columns can accommodate that data type.
This will always return the same data structure so SSRS will be happy, then you will need to handle which columns to display your data from based on what gets returned, hence why I added the result type to the results so you can test that from within the report.

select COUNT and then condition SQL

I have a condition which based on my Count result, it should skip or include a join in my query,to make short the story,how to implement such a thing in SQL:
select count(names) as rslt
if(rslt)>0 then
select......join tables
else
Select...
as you see I want to say if the count is >0 then do the join otherwise it should skip then join and go to the next line,how should I achieve this?
DECLARE #Name INT
SELECT
#Name = COUNT(names)
FROM Table
IF #Name > 0
BEGIN
PRINT 'Do somthing'
END
ELSE
PRINT 'Do something else'
END
Just change the PRINT statements to your query logic
If you want to check if a resulting query returns any row (>0) then you should use an IF with an EXISTS rather than using COUNT. EXISTS will make the SQL engine stop running once it finds at least 1 row, while COUNT will force to actually count all records.
IF EXISTS (SELECT 1 FROM YourTable WHERE names IS NOT NULL)
BEGIN
SELECT
YourColumn
FROM
Table1
INNER JOIN Table2 ON --...
END
ELSE
BEGIN
SELECT
YourColumn
FROM
Table1
END
If on the other hand you need to check a specific amount, then you will have to COUNT and assign to variable.
DECLARE #CountTotal INT = (SELECT COUNT(names) FROM YourTable)
IF #CountTotal > 100
BEGIN
SELECT
YourColumn
FROM
Table1
INNER JOIN Table2 ON --...
END
ELSE
BEGIN
SELECT
YourColumn
FROM
Table1
END
DECLARE #reslt integer
#reslt = select count(names)
if #reslt >0 then
select......join tables
You need to put it in a variable and then call it.
You can also use dynamic query like below:
DECLARE #SQL NVARCHAR(MAX);
SELECT #SQL = N'SELECT *
FROM T1 ' + CASE WHEN (SELECT COUNT(names) FROM table1) > 0 THEN +
' INNER JOIN T2 ON T1.Id = T2.Id ' ELSE '' END
PRINT #SQL
EXEC sp_executesql #SQL;
Use CASE function, something like this :
Select count(CustomerID),
CASE
WHEN count(CustomerID) > 30 THEN "The quantity is greater than 30"
WHEN count(CustomerID) = 30 THEN "The quantity is 30"
ELSE "The quantity is something else"
END
FROM Customers;
You Can try below method as well.
if((select count(Name) from tableName)>0)
begin
select 1
end
else
begin
select 2
end
No need to use one temp variable to store the count .

ISNULL function in SQL Server 2008 not working properly

Assume this script:
DECLARE #result TABLE(Id BIGINT);
DELETE FROM [Products].[Product]
OUTPUT DELETED.[Id] INTO #result
WHERE [Products].[Product].[Id] = 1589;
So in continues I try :
1
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
When [Id] is null returned null (nothing), but this one returned -1:
2
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
SELECT CAST(ISNULL(#mi, -1) AS BIGINT) AS N'RetValId'
Why? where is the problem with first script?
Update
So is there any way to check if the Deleted Id is null returned -1 And if not Returned Id without declare another variable? what is the simplest way?
If you have no entry for the ID 1589, then in the DELETED table there will be no record, if you have it then it should return 1589.
So if you don't have I think it simple returns nothing, because this statement has no input row:
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
(If you SELECT * from #result it should be no rows there)
The second one return the -1 because you set first to the variable which is getting the NULL value after the select.
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
(If you select only #mi after this, then it should be NULL)
I think that is the explanation
UPDATED:
May you can try a small trick to achive it without an other varriable:
SELECT CAST(ISNULL(MAX([ID]),-1) AS BIGINT) AS N'RetValId' FROM #result;
Because of MAX the insie statement will be NULL, so here is the trick. If something was deleted, then the ID will be there.
I hope it helped.
You can use a derived table that will return one row with -1 and then do an outer apply on #result.
select isnull(R.Id, T.Id) RetValId
from (values(-1)) as T(Id)
outer apply #result as R
An easy way to return null if no rows where deleted is the ##rowcount variable. It contains the number of rows affected by the previous operation:
DELETE FROM [Products].[Product]
WHERE [Products].[Product].[Id] = 1589;
IF ##ROWCOUNT = 0
return null
return 1589

Select with IN and Like

I have a very interesting problem. I have an SSRS report with a multiple select drop down.
The drop down allows to select more than one value, or all values.
All values is not the problem.
The problem is 1 or the combination of more than 1 option
When I select in the drop down 'AAA' it should return 3 values: 'AAA','AAA 1','AAA 2'
Right now is only returning 1 value.
QUESTION:
How can make the IN statement work like a LIKE?
The Drop down select
SELECT '(All)' AS team, '(All)' AS Descr
UNION ALL
SELECT 'AAA' , 'AAA'
UNION ALL
SELECT 'BBB' , 'BBB'
Table Mytable
ColumnA Varchar(5)
Values for ColumnA
'AAA'
'AAA 1'
'AAA 2'
'BBB'
'BBB 1'
'BBB 2'
SELECT * FROM Mytable
WHERE ColumnA IN (SELECT * FROM SplitListString(#Team, ',')))
Split function
CREATE FUNCTION [dbo].[SplitListString]
(#InputString NVARCHAR(max), #SplitChar CHAR(1))
RETURNS #ValuesList TABLE
(
param NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #ListValue NVARCHAR(max)
DECLARE #TmpString NVARCHAR(max)
DECLARE #PosSeparator INT
DECLARE #EndValues BIT
SET #TmpString = LTRIM(RTRIM(#InputString));
SET #EndValues = 0
WHILE (#EndValues = 0) BEGIN
SET #PosSeparator = CHARINDEX(#SplitChar, #TmpString)
IF (#PosSeparator) > 1 BEGIN
SELECT #ListValue = LTRIM(RTRIM(SUBSTRING(#TmpString, 1, #PosSeparator -1 )))
END
ELSE BEGIN
SELECT #ListValue = LTRIM(RTRIM(#TmpString))
SET #EndValues = 1
END
IF LEN(#ListValue) > 0 BEGIN
INSERT INTO #ValuesList
SELECT #ListValue
END
SET #TmpString = LTRIM(RTRIM(SUBSTRING(#TmpString, #PosSeparator + 1, LEN(#TmpString) - #PosSeparator)))
END
RETURN
END
You can't. But, you can make the like work like the like:
select *
from mytable t join
SplitListString(#Team, ',') s
on t.ColumnA like '%'+s.param+'%'
That is, move the split list to an explicit join. Replace with the actual column name returned by the function, and use the like function.
Or, if you prefer:
select *
from mytable t cross join
SplitListString(#Team, ',') s
where t.ColumnA like '%'+s.param+'%'
The two versions are equivalent and should produce the same execution plan.
Better approach would be to have a TeamsTable (teamID, teamName, ...) and teamMembersTable (teamMemberID, teamID, teamMemberDetails, ...).
Then you an build your dropdown list as
SELECT ... FROM TeamsTable ...;
and
SELECT ... FROM teamMembersTable WHERE teamID IN (valueFromYourDropDown);
Or you can just store your teamID or teamName (or both) in your (equivalent of) teamMembersTable
You're not going to get IN to work the same as LIKE without a lot of work. You could do something like this though (and it would be nice to see some of your actual data though so we could give better solutions):
SELECT *
FROM table
WHERE LEFT(field,3) IN #Parameter
If you'd like better performance, create a code field on your table and update it like this:
UPDATE table
SET codeField = LEFT(field,3)
Then just add an index on that field and run this query to get your results:
SELECT *
FROM table
WHERE codeField IN #Parameter

how to return a cell into a variable in sql functions

I want to define a scaler function which in that I'm going to return the result into a variable but I do not know how to do this.
CREATE FUNCTION dbo.Funname ( #param int )
RETURNS INT
AS
declare #returnvar int
select #returnvar = select colname from tablename where someconditions = something
return(#returnvar)
I want to make a function something like the top. I mean the result of the select statement which is:
select colname from tablename where someconditions = something
Is only a single cell and we are sure about it. I want to store it into a variable and return it from the function. How can I implement this thing?
I should probably mention that scalar UDFs do come with a considerable health warning and can cause performance issues depending upon how you use them.
Here's an example though.
CREATE FUNCTION dbo.Funname ( #param INT )
RETURNS INT
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN (SELECT number FROM master.dbo.spt_values WHERE number < #param)
END
In the above example I didn't use a variable as it is redundant. The version with variable is
BEGIN
DECLARE #Result int
SET #Result = (SELECT number FROM master.dbo.spt_values WHERE number < #param)
RETURN #Result
END
For both of the above you would need to be sure the Query returned at most one row to avoid an error at runtime. For example
select dbo.Funname(-1) Returns -32768
select dbo.Funname(0) Returns error "Subquery returned more than 1 value."
An alternative syntax would be
BEGIN
DECLARE #Result int
SELECT #Result = number FROM master.dbo.spt_values WHERE number < #param
RETURN #Result
END
This would no longer raise the error if the subquery returned more than one value but you would just end up with an arbitrary result with no warning - which is worse.
Following Comments I think this is what you need
CREATE FUNCTION dbo.getcustgrade(#custid CHAR(200))
RETURNS INT
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN
( SELECT [cust grade]
FROM ( SELECT customerid,
DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS [cust grade]
FROM Orders
GROUP BY CustomerID
)
d
WHERE customerid = #custid
)
END