show result of multi sql procedure and use it in view - sql

i have a table that named 'place'
create table place( ID int , Name varchar)
i have a procedure that named 'placeshow' with one parameter
my end is show all result of procedure for table place rows
for example :
exec placeshow #placeid=1
exec placeshow #placeid=2
exec placeshow #placeid=3
exec placeshow #placeid=4
.......
.......
exec placeshow #placeid=5
i need to run code like some this and show the result of that query
at the end i should save the result in a view
please help me

You can try something like below,
DECLARE #Sql VARCHAR(MAX) = ''
SELECT #Sql = (SELECT '
;
exec PlaceShow ' + CAST(ID aS VARCHAR(10))
FROM Place
FOR XML PATH (''), TYPE).value('.[1]', 'varchar(max)')
INSERT INTO tbl_output --this is the table where you can insert your results and use however you want
EXEC(#Sql)

if you don't have control on them?... so you can use loop..
for example..
DECLARE #resultTable TABLE(id int,col1 vrachar(10),col2 varchar(20))
declare #temp int
declare #temp1 int
WHILE #temp <= (select count(placeid) from Place)
BEGIN
Select #temp1 = placeid
From
(
Select
Row_Number() Over (Order By placeid) As RowNum
, *
From TABLE
) t2
Where RowNum = placeid
if not exists(select 1 from Place where id=#temp1)
begin
INSERT INTO #resultTable
EXEC placeshow #placeid=#temp1
end
END;

Related

Cross-database subquery on using database name stored in record

Is the script structure below possible?
Select
*,
(Select Count(*)
from [A.DatabaseName].dbo.TableA
where SomeID = A.SomeID) As Total
From
[Database1].dbo.Table1 A
The subquery above is dependent on the database name from [Database1].
Is this doable? If yes, how can this be implemented?
The Dynamic Query will help you.
DECLARE #DBName VARCHAR(100),#SQLQuery VARCHAR(1000)
SELECT #DBName = A.DatabaseName FROM [Database1].dbo.Table1
SELECT #SQLQuery = 'Select
*,
(Select Count(*)
from '+#DBName+'.dbo.TableA
where SomeID = A.SomeID) As Total
From
[Database1].dbo.Table1 A'
EXEC (#SQLQuery)
---> Edit
I think i understand the weird thing you are tying to do.
You store some database name into a table and the want to call if from a subquery.
You have to try something like this :
CREATE DATABASE test
use test
CREATE TABLE client
(
ID IDENTITY(1,1),
[name] varchar(20)
)
INSERT INTO client
([name])
VALUES
('Jean'), ('Paul'), ('Mark'), ('Pierre');
CREATE TABLE allTable
(
NomSchema VARCHAR(200),
NomTable VARCHAR(200)
)
INSERT INTO allTable
VALUES
(
'TEST','client'
)
IF OBJECT_ID('tempdb..#ResultA') IS NOT NULL
DROP TABLE #ResultA
BEGIN TRAN
DECLARE #sql VARCHAR(200);
SELECT TOP(1) * INTO #resultA FROM allTable
SET #sql = 'SELECT * FROM ' + (SELECT quotename(#resultA.NomSchema) + '.dbo.' + quotename(#resultA.NomTable) FROM #resultA)
SELECT #sql
EXEC(#sql)
DROP TABLE #resultA
COMMIT
GO
-- DROP DATABASE TEST

Reorder columns in final stored procedure SELECT / OUTPUT

I need to reorder columns in the final SELECT statement in a stored procedure. Column orders needs to be fetched from another table.
I have a solution based on dynamic SQL. Is there any better way to do it? I have around 100 columns to return with millions of rows for an Excel export. Is there any other performance optimized solution other than a dynamic query?
Please find sample code below for my current solution.
IF OBJECT_ID( 'tempdb..#TempColumns') IS NOT NULL
BEGIN
DROP TABLE #TempColumns
END
IF OBJECT_ID( 'tempdb..#TempColumnsOrder') IS NOT NULL
BEGIN
DROP TABLE #TempColumnsOrder
END
CREATE TABLE #TempColumns
(
ID INT IDENTITY,
FirstName VARCHAR(MAX),
LastName VARCHAR(MAX),
Gender VARCHAR(MAX)
)
INSERT INTO #TempColumns
VALUES ('ABC', 'DEF', 'MALE'), ('PR', 'ZA', 'FEMALE'), ('ERT', 'GFG', 'MALE')
CREATE TABLE #TempColumnsOrder
(
ID INT IDENTITY,
ColumnName VARCHAR(MAX),
ColumnOrder INT
)
INSERT INTO #TempColumnsOrder
VALUES ('FirstName', 3), ('LastName', 2), ('Gender', 1)
SELECT * FROM #TempColumns
SELECT * FROM #TempColumnsOrder
DECLARE #script VARCHAR(MAX)
SELECT #script = 'SELECT '
SELECT #script = #script + ColumnName + ','
FROM #TempColumnsOrder
ORDER BY ColumnOrder
PRINT #script
SELECT #script = SUBSTRING(RTRIM(#script), 1, LEN(RTRIM(#script)) - 1)
SELECT #script = #script + ' FROM #TempColumns'
EXEC (#script)
IF OBJECT_ID( 'tempdb..#TempColumns') IS NOT NULL
BEGIN
DROP TABLE #TempColumns
END
IF OBJECT_ID( 'tempdb..#TempColumnsOrder') IS NOT NULL
BEGIN
DROP TABLE #TempColumnsOrder
END
Thanks for reply, Is there any better way in Dynamic SQL other than what i did?
You can eliminate the unsupported string concatenation you are using, and modernize and simply the code:
DROP TABLE IF EXISTS #TempColumns
DROP TABLE IF EXISTS #TempColumnsOrder
CREATE TABLE #TempColumns
(
ID INT IDENTITY,
FirstName VARCHAR(MAX),
LastName VARCHAR(MAX),
Gender VARCHAR(MAX)
)
INSERT INTO #TempColumns
Values('ABC','DEF','MALE'),('PR','ZA','FEMALE'),('ERT','GFG','MALE')
CREATE TABLE #TempColumnsOrder
(
ID INT IDENTITY,
ColumnName VARCHAR(MAX),
ColumnOrder INT
)
INSERT INTO #TempColumnsOrder
Values('FirstName',3), ('LastName',2), ('Gender',1)
SELECT * FROM #TempColumns
SELECT * FROM #TempColumnsOrder
DECLARE #script VARCHAR(MAX) = concat(
'SELECT ',
(select STRING_AGG(QUOTENAME(ColumnName),', ') WITHIN GROUP (ORDER BY ColumnOrder)
FROM #TempColumnsOrder),
' FROM #TempColumns')
print #script
EXEC (#script)
DROP TABLE IF EXISTS #TempColumns
DROP TABLE IF EXISTS #TempColumnsOrder
SELECT #script = #script + ColumnName + ',' FROM #TempColumnsOrder
ORDER BY ColumnOrder
The behavior of aggregate string concatenation with the above technique is not guaranteed. The actual behavior is plan-dependent so you may not get the desired results.
In SQL Server 2017 and Azure SQL Database, STRING_AGG is the proper method:
SELECT STRING_AGG(ColumnName, ',') WITHIN GROUP(ORDER BY ColumnOrder)
FROM #TempColumnsOrder;
In older SQL Versions like SQL Server 2012, the best method is with XML PATH():
SELECT #script = #script +
STUFF((SELECT ',' + ColumnName
FROM #TempColumnsOrder
ORDER BY ColumnOrder
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'');
See this answer for details about how the above query works.

Select all from tables where table names are from another table in SQL

I have a temp table which has a TableName column. I would like to loop through the temporary table and select everything in the the table (where table is the TableName column in the temp table).
I have been looking through the following link and related links however I am unable to adapt it to my needs. Any help is greatly appreciated.
I am using SQL Server 2014
Something which i have tried
Declare #id int
WHILE EXISTS(SELECT * FROM ##tt_tableList)
BEGIN
Select Top 1 #id = Id from ##tt_tableList
-- Do the work --
declare #query nvarchar(max)
set #query = 'Select * from (select TableName from ##tt_tablelist where id = '' +Cast(#id as nvarchar(50))+'')'
select #query
declare #tableName nvarchar(50)
set #tableName = (select TableName from ##tt_tableList where id = #id)
select #tableName
execute(#query)
-- Scrap the ID and Move On --
Delete ##tt_tableList where ID = #id
END
If I understood you correctly this is what you are asking for:
DECLARE #tbl table (TableName varchar(50))
insert into #tbl values ('SomeTableName')
insert into #tbl values ('AnotherTableName')
DECLARE #Tables VARCHAR(8000)
SELECT #Tables = COALESCE(#Tables + CHAR(13), '') + 'SELECT * FROM '+ TableName
FROM #tbl
exec(#Tables)
Just insert your table names in #tbl
I tried this based on answer from one of our fellow stack overflower and it works.
DECLARE #Tables VARCHAR(8000)
SELECT #Tables = COALESCE(#Tables + CHAR(13), '') + 'SELECT * FROM '+ TableName + ' Where Event like ''%CM_Manual_Change%'''
FROM ##tt_tableList
select #Tables
exec(#Tables)

How to run string math expression in SQL Server (trigger or function)

I want to run:
select Mycalculatefunction('((3*4)-3)*5')
select ('((3*4)-3)*5')
OUTPUT: ((3*4)-3)*5 wrong (not int value)
My desired output is: 45
I defined a stored procedure:
create PROCEDURE dbo.Eval
(#exp varchar(MAX))
AS
SET NOCOUNT ON
DECLARE #SQLString NVARCHAR(MAX)
SET #SQLString = 'SELECT '+#exp
EXEC sp_executesql #SQLString
I call it:
exec dbo.Eval '((3*4)-3)*5'
How can I do in this process is the trigger?
Your SP is vulnerable to injection. F.e. I pass exec dbo.Eval '1;DROP TABLE some_table;'. Better use xml.query:
CREATE PROCEDURE dbo.Eval
#formula nvarchar(max)
AS
DECLARE #sql nvarchar(max)
SELECT #sql = N'
DECLARE #x xml = ''''
SELECT CAST(#x.query('''+#formula+''') as nvarchar(max))'
EXEC sp_executesql #sql
Then
EXEC dbo.Eval '((3*4)-3)*5'
Output:
45
Triggers part (as there were no info about your tables, just general explanation, I add full batch with comments):
--Create table that will store Formulas
CREATE TABLE Formulas (
ID int IDENTITY(1,1) NOT NULL,
Formula nvarchar(max) NULL,
CONSTRAINT PK_ID PRIMARY KEY (ID)
)
GO
--Create table to store results of the formulas
CREATE TABLE Results (
T1_ID int NOT NULL,
Result int NULL
)
GO
--Linked by ID
ALTER TABLE Results ADD CONSTRAINT FK_Formulas_Results FOREIGN KEY (T1_ID)
REFERENCES Formulas (ID)
GO
--Create a Table Valued Parameter
CREATE TYPE FormulaResults AS TABLE (
ID int NOT NULL,
Formula nvarchar(max) NULL
)
GO
--Create a procedure to do the count
CREATE PROCEDURE dbo.GetResults
#TVP FormulaResults READONLY
AS
DECLARE #sql nvarchar(max)
SELECT #sql = N'DECLARE #x xml = '''' '
SELECT #sql = #sql + 'SELECT '+CAST(ID as nvarchar(max))+' as ID, CAST(#x.query('''+Formula+''') as nvarchar(max)) UNION ALL '
FROM #TVP
SELECT #sql = LEFT(#sql,LEN(#sql)-LEN('UNION ALL '))
EXEC sp_executesql #sql
GO
--Create a trigger that will count formula after insert and update
CREATE TRIGGER GetResultsTrigger
ON Formulas
AFTER INSERT, UPDATE
AS
DECLARE #FormulaTVP AS FormulaResults
DECLARE #Results TABLE(
T1_ID int NOT NULL,
Result int NULL
)
INSERT INTO #FormulaTVP
SELECT *
FROM inserted
INSERT INTO #Results
EXEC dbo.GetResults #FormulaTVP
MERGE Results r
USING #Results s
ON r.T1_ID = s.T1_ID
WHEN NOT MATCHED THEN
INSERT VALUES (s.T1_ID, s.Result)
WHEN MATCHED THEN
UPDATE SET Result = s.Result;
After that run:
INSERT INTO [Formulas] VALUES
('1+3'),('2+2*8')
SELECT [ID],
[Formula]
FROM [Test].[dbo].[Formulas]
SELECT [T1_ID],
[Result]
FROM [Test].[dbo].[Results]
Output:
ID Formula
1 1+3
2 2+2*8
T1_ID Result
1 4
2 18
image 1
ALTER FUNCTION [dbo].[Calculate]
( #expression AS VARCHAR(MAX)
)
RETURNS xml
AS
BEGIN
-- routine body goes here, e.g.
-- SELECT 'Navicat for SQL Server'
DECLARE #result xml
declare #x xml=''
--I can not pass as a parameter
select #result=#x.query(('(4*3)*5-10'))
return #result;
END
i call this function:
SELECT CAST(CAST(CAST(dbo.[Calculate]('How do I pass parameters') AS XML) AS VARCHAR(100)) AS DECIMAL(4,2))
Output:
50.00
select #result=#x.query('sql:variable("#expression")')
result: '2+2' :(((

Execute Stored Procedure having a query as a parameter

How can I execute the sp_1 for every ProductId and get a result set?
EXEC sp_1 (SELECT ID FROM Products)
Try this way. No direct query it seems.
execute sp for each row
or try this , make small changes if needed.Use temp table to get values out of sp. Use the below inside a sp if needed.
begin
declare #ID int
declare #temp table (col1 int)
declare cur cursor for select distinct ID from products
open cur
fetch next from cur into #ID
truncate table #temp
while(##FETCH_STATUS=0)
begin
insert into #temp (<'cols/output from procedure'>) exec (#ID)
end
select * from #temp
end
I would store the id's in a temp table and use a WHILE loop (AVOID CURSORS!)
DECLARE #prodid INT
SELECT prodid, 0 as Processed INTO #prod_ids FROM Products
WHILE EXISTS (SELECT prodid FROM #prod_ids WHERE Processed = 0)
BEGIN
SELECT TOP 1 #prodid = prodid FROM #prod_ids WHERE Processed = 0
EXEC sp_1(#prodid)
UPDATE #prod_ids SET Processed = 1 WHERE prodid = #prodid
END
With dynamic query in SQL Server:
declare #cadena varchar(max) = ''
select #cadena = #cadena + 'exec sp_1 ' + ltrim(ID) + ';'
from Products;
exec(#cadena);