Table-valued function - duplicate table declaration - sql

I am using table-valued function in SQL Server to return data either with ties or without on some condition specified.
Now the solution works fine but I do not like the fact that I have to declare the table twice - is there any workaroud? I could probably instead of inserting into #tmp table use #ReturnTable but that data would have to be deleted once select top 1 is queried at the end of the function.
RETURNS #ReturnTable TABLE
(
idTable INT,
idOther INT,
name VARCHAR(30)
)
AS
BEGIN
DECLARE #tmp TABLE
(
idTable INT,
idOther INT,
name VARCHAR(30)
)
INSERT INTO #tmp
SELECT idTable,
idOther,
name
FROM SomeTable
IF (some condition)
BEGIN
INSERT INTO #ReturnTable
SELECT TOP 1 WITH TIES idTable,
idOther,
name
FROM #tmp
ORDER BY (some ordering)
END;
ELSE
BEGIN
INSERT INTO #ReturnTable
SELECT TOP 1 idTable,
idOther,
name
FROM #tmp
ORDER BY (some other ordering)
END;
RETURN;
END;

Try re-writing your function to Inline table valued function.
Based on the condition you have to use either ROW_NUMBER or DENSE_RANK window function. TOP 1 with TIES can be achieved using DENSE_RANK/RANK
RETURNS TABLE
AS
RETURN
(SELECT idtable,
idother,
NAME
FROM (SELECT CASE
WHEN (some condition) THEN Dense_rank()OVER(ORDER BY (some ordering))
ELSE Row_number()OVER(ORDER BY (some other ordering))
END AS RN,
idtable,
idOther,
NAME
FROM sometable)a
WHERE RN = 1)

Related

Function to multiple tables

I have this function, but I wanted to pass a table so as to use the same function to get the job done for multiple tables. For example, I want this function work for table1, and table2. But it is just for table1 currently. I was trying to use a dynamic sql in vain; it doesn't pass the parameter selected.
Can someone help? Give me guide on how to pass table as a parameter.
Sample data, table1
CREATE TABLE table1 (id int identity (1,1), name varchar(60))
INSERT INTO table1
VALUES ('a1, a2, a9, a8')
Sample data, table2
CREATE TABLE table2 (id int identity (1,1), name varchar(60))
INSERT INTO table2
VALUES ('a1, a2, a9, a8')
The function:
CREATE FUNCTION f_split
(#id INT)
RETURNS #ab
TABLE (name VARCHAR(20),
ab1 VARCHAR(5)
)
AS
BEGIN
DECLARE #temp TABLE (rn INT, name VARCHAR(5))
INSERT INTO #temp(rn, name)
SELECT ROW_NUMBER() OVER(ORDER BY LTRIM(RTRIM(Split.a.value('.', 'NVARCHAR(MAX)'))) ASC) rn, LTRIM(RTRIM(Split.a.value('.', 'NVARCHAR(MAX)'))) Result
FROM
(
SELECT CAST('<X>'+REPLACE([name], ',', '</X><X>')+'</X>' AS XML) AS String
FROM table1 where id = #id
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)
ORDER BY 1
INSERT INTO #ab
SELECT * FROM #temp
RETURN
END
This gives the result from table1.
SELECT * FROM F_SPLIT(1)
But I want the same function to work for table2 as well.
Any help is appreciated.
Use a partitioned view, which will allow you to specify the table name as a parameter in the where clause.
Start by creating a view that unions the two tables, plus an additional column to indicate which table the row comes from.
CREATE VIEW BothTables AS
SELECT 'Table1' TableName, * FROM Table1
UNION ALL
SELECT 'Table2' TableName, * FROM Table2
Then modify your function. When you pass the table name, use it to select a subset of rows from the view. So instead of
SELECT CAST('<X>'+REPLACE([name], ',', '</X><X>')+'</X>' AS XML) AS String
FROM table1
WHERE id = #id
Use
SELECT CAST('<X>'+REPLACE([name], ',', '</X><X>')+'</X>' AS XML) AS String
FROM BothTables
WHERE TableName = #TableName
AND id = #id

SQL FUNCTION - one alias in SELECT AND WHERE

I want to insert to NewTable some id(found by calledMethod) from table 'inserted' when this id actually it's not in this table(NewTable)
Actually i'm using this method (calledMethod)twice. How to reduce this using for example alias?
CREATE TRIGGER TriggerName
ON Table
AFTER INSERT
AS
BEGIN
INSERT INTO NewTable
(
FirstId
SecondId
)
SELECT
I.ID
CalledMethod(I.Name)
FROM INSERTED I
WHERE CalledMethod(I.Name)
NOT IN (SELECT SecondId FROM NewTable)
END
GO
The second problem occures when I want insert two rows at the same time.
Insert Into Table
(
Name
)
Values
('ro'),('ro-RO')
In this situation, the method returns the same index and both will be added. How to resolve this problem.
In this situation, the method returns the same index
This is example of calledMethod
CREATE FUNCTION CalledMethod
(
#internalName nvarchar(50)
)
RETURNS int
AS
BEGIN
return case
when #internalName Like 'ro%' then 6
when #internalName Like 'sk%' then 7
when #internalName Like 'bg%' then 9
end
END
I believe this is what you need:
CREATE TRIGGER TriggerName
ON Table
AFTER INSERT
AS
BEGIN
INSERT INTO NewTable
(
FirstId
SecondId
)
SELECT
min(I.ID),
x.called
FROM INSERTED I
CROSS APPLY
(SELECT CalledMethod(I.Name) called) x
WHERE
x.called NOT IN (SELECT SecondId FROM NewTable)
GROUP BY x.called
END

Assign multiple values to Table variable in SQL

DECLARE #ID INT
SET #ID = (select top 1 USER_REQ_JOB_ID
from T8504_USER_REQ_JOB
where JOB_GRP_ID = 160
order by LST_UPDT_TS desc)
SELECT INPUT_PARM_VAL_TX
from TBL_RPT_JOB_INPUT_PARAM
where USER_REQ_JOB_ID = #ID
This returns these results:
USA
USCC
6
7
2
These five records what I get I want to assign to five different variables to use in stored procedure.
I was trying with table variable like this :
declare #CID table (
Region Char(3)
,Segment Char(3)
,MasterContractId int
,ctcid int
,templateid int)
insert into #CID (Region,Segment,MasterContractId,ctcid,templateid)
But how to insert that 5 rows here?
INSERT INTO #CID
select * from
(
select
'Temp' + convert(char(1), row_number() over (order by (select 0))) as columnName,
INPUT_PARM_VAL_TX as Value
from TBL_RPT_JOB_INPUT_PARAM where USER_REQ_JOB_ID = #ID
) d
pivot
(
max(value)
for columnname in (Temp1, Temp2, Temp3, Temp4, Temp5)
) piv;
See if this helps.
Take a look at this fiddle for an example.
Courtesy:
Add row number to this T-SQL query
Efficiently convert rows to columns in sql server
EDIT: The sql adds an extra column to generate row numbers to use it as an extra column, which is pivoted as column heading.
it's really gross, but one way you could probably do it is this (though you'll need to apply it to your case):
http://sqlfiddle.com/#!6/d41d8/21507
declare #table TABLE (value varchar(50))
INSERT INTO #table
VALUES ('first')
INSERT INTO #table
VALUES ('second')
INSERT INTO #table
VALUES (3)
INSERT INTO #table
VALUES (4)
DECLARE #temp TABLE (id int identity(1,1), value varchar(50))
INSERT INTO #temp
SELECT [value]
FROM #table t
SELECT *
FROM #temp
DECLARE #CID TABLE (Region varchar(50), cont varchar(50), another int, andAnother int)
INSERT INTO #CID
(
Region,
cont,
another,
andAnother
)
VALUES
(
(SELECT value FROM #temp WHERE id = 1), -- Region - varchar
(SELECT value FROM #temp WHERE id = 2), -- cont - varchar
(SELECT value FROM #temp WHERE id = 3), -- another - int
(SELECT value FROM #temp WHERE id = 4) -- andAnother - int
)
SELECT * FROM #cid
note that i assumed you're using mssql, you did not specify

optimizing SQL query with multiple keys

I have a table in a database with a primary key, and a 'second' key as well. This second key can have the same value occur more than once in the table, but often i only want to return the most recent row for that second key. I have an existing query that works below, but I feel like it's very ugly and there should be a simpler way to do this instead of creating a table variable, going through a loop, and inserting 1 row into the table variable on each pass through the loop. Am i making this too hard?
declare #RowCnt int
declare #MaxRows int
declare #secondID as uniqueidentifier
DECLARE #retList TABLE(
firstGUID uniqueidentifier,
secondGUID uniqueidentifier,
name nvarchar(50),
DateCreated datetime
)
select #RowCnt = 1
declare #Import table (rownum int IDENTITY (1, 1) Primary key NOT NULL , secondGUID uniqueidentifier)
insert into #Import (secondGUID) SELECT DISTINCT dbo.TestTable.secondGUID FROM dbo.TestTable
select #MaxRows=count(*) from #Import
while #RowCnt <= #MaxRows
begin
select #secondID=secondGUID from #Import where rownum = #RowCnt
INSERT INTO #retList
SELECT TOP (1) firstGUID,secondGUID,name,datecreated
FROM dbo.TestTable
WHERE dbo.TestTable.secondGUID = #secondID
ORDER BY DateCreated Desc
Set #RowCnt = #RowCnt + 1
END
select * from #retList
EDIT:
for example, imagine the table has these values
firstGUID secondGUID Name DateCreated
EAD50999-E9B1-43F0-9FA6-615405FA5A9A 6163B6ED-6AF4-494E-ACE6-184F4804847B Test1 2014-04-11 15:12:36.303
A9645486-1021-4E98-92AC-1205CC3FB9D3 6163B6ED-6AF4-494E-ACE6-184F4804847B Test2 2014-04-10 15:21:46.087
DEE375BB-BFAF-44BE-AC64-06D7702E2ACB 3BD0A2F0-4E44-43B9-BD24-003B518609C7 Test3
2014-04-11 15:22:37.097
I only want the Test1 and Test3 rows to be returned.
You could use SQLServer's analytical functions:
select firstGUID, secondGUID, name, datecreated
from (select t.*,
rank() over (partition by secondGUID order by datecreated desc) r
from TestTable t) ilv
where r=1
I'm not 100% sure I understand what you're asking, but it sounds like you want to select only the rows containing the max DateCreated. The normal way of doing that is to join with a subselect that uses a group by clause, eg.:
select tt.*
from TestTable tt
join (
select firstguid, max(DateCreated) as maxdate
from TestTable
group by firstguid
) gtmp on tt.firstguid = gtmp.firstguid and tt.dateCreated = gtmp.maxdate

Problem with if-statement used at Table-returned-function in SQL

I have simplified my function to the following:
create function [dbo].[UserSuperTeams](#ProjectId int)
returns table
as
return
if #ProjectId=0
begin
select TeamId from TblTeam t
union
select 0 as TeamId
end
else
begin
select t.TeamId from TblTeam t
union
select 1 as TeamId
end;
go
I cannot make it work.. It seems I have some syntax errors, but I cannot figure out how to make it work.. Any idea?
If you are going to use t-sql code in the function, you need to define the table in the 'returns' section, then populate it with insert statements:
create function [dbo].[UserSuperTeams](#ProjectId int)
returns #results table (
TeamId int
) as begin
if #ProjectId=0 begin
insert #results (TeamId)
select TeamId from TblTeam t
union
select 0 as TeamId
end
else begin
insert #results (TeamId)
select t.TeamId from TblTeam t
union
select 1 as TeamId
end;
return
end
You must declare the table with a temporary name and a schema in the function declaration, then insert into it in the function:
create function [dbo].[UserSuperTeams](#ProjectId int)
returns #mytable table (TeamID int)
as
...
and then something like:
INSERT INTO #mytable
select t.TeamId from TblTeam t
union
select 1 as TeamId
This works especially well for functions that insert several rows into the table.
Alternatively, if you only wish to return the results of a single SELECT, you can use an inline return:
BEGIN
RETURN (
select t.TeamId from TblTeam t
union
select 1 as TeamId
)
END
As Jeremy said, or if it really is very like your simplified example you can do:
create function [dbo].[UserSuperTeams](#ProjectId int)
returns table
as
return (select TeamId from TblTeam t
union
select CASE WHEN #ProjectId = 0 THEN 0 ELSE 1 END as TeamId
)
go
(i.e. you may not have to define the table var/schema)
this code is working for me :
DROP FUNCTION IF EXISTS [dbo].[test]
GO
CREATE FUNCTION [dbo].[TEST]
(
#ACTIVEONLY bit
)
RETURNS #TST TABLE (column1 char)
AS
BEGIN
IF #ACTIVEONLY = 1
BEGIN
INSERT INTO #TST(column1) VALUES('A')
END
ELSE
BEGIN
INSERT INTO #TST(column1) VALUES('B')
END
RETURN
END
GO
SELECT * FROM [dbo].[TEST](1)
GO
SELECT * FROM [dbo].[TEST](0)
GO