问题
I want to sum up values from several databases. At this moment I have three databases: SPA_PROD, SPB_PROD and SPC_PROD.
My SQL query:
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[TESTSUM]')
AND TYPE IN (N'P',N'PC'))
DROP PROCEDURE [dbo].[TESTSUM]
GO
CREATE PROC TESTSUM
AS
BEGIN
DECLARE @dbName SYSNAME,
@ObjectSUM INT,
@d datetime
SET @d = '20141113'
DECLARE @SQL NVARCHAR(MAX)
DECLARE @DBObjectStats TABLE (
--DBName SYSNAME,
DBObjects INT)
DECLARE curAllDBs CURSOR FOR
SELECT name
FROM MASTER.dbo.sysdatabases
WHERE name like '%PROD'
ORDER BY name
OPEN curAllDBs
FETCH curAllDBs INTO @dbName
WHILE (@@FETCH_STATUS = 0) -- db loop
BEGIN
--SQL QUERY
SET @SQL = 'select @dbObjects = sum(doctotal) from ' +
QuoteName(@dbName) + '..Invoice
where DocDate = ''' + cast(@d as varchar(25)) + ''''
PRINT @SQL -- Debugging
EXEC sp_executesql @SQL, N'@dbObjects int output',
@dbObjects = @ObjectSUM output
INSERT @DBObjectStats
SELECT @ObjecSUM
FETCH curAllDBs INTO @dbName
END
CLOSE curAllDBs
DEALLOCATE curAllDBs
-- Return results
SELECT sum(DBObjects) [InvoiceSUM] FROM @DBObjectStats
END
GO
-- Execute stored procedure
EXEC TESTSUM
GO
And this work perfect and giving me right sum from all my DBs: 120 000$ ( 25 000 from SPA_PROD , 95 000 SPC_PROD and 0 (NULL) from SPB_PROD.
What I want to do:
I would like to parametrize, which allows me to choose date and databases. For example I want to choose SPA_PROD and SPB_PROD with date 2014-01-01 in another case I want all databases (SPA + SPB + SPC with another date.
Is this even possible? Any ideas?
I can use everything what gives me SQL Server 2012 and T-SQL. Maybe this technology offers me easiest way to do this.
I am also using SAP Crystal Reports to convert SQL output into a beautiful report.
Sorry for my English and I tried to describe to you my problem as far as I could. If you want any additional information which helps u to help me -> ask me :).
回答1:
You can create a User-Defined Table Type:
CREATE TYPE DBTable AS TABLE
(
DBName VARCHAR(128)
);
You can use it as an input parameter of your stored procedure. As well as the date parameter.
CREATE PROCEDURE TESTSUM
@Databases DBTable READONLY
,@Date DATETIME
AS
BEGIN
...
...
...
You call it like this:
DECLARE @T AS DBTable;
DECLARE @D AS DATETIME = GETDATE();
INSERT INTO @T VALUES ('DB1', 'DB2', 'DB3')
EXEC TESTSUM @T, @D
回答2:
maybe instead of
SELECT name
FROM MASTER.dbo.sysdatabases
use
SELECT name
FROM #temptable
and insert into #temptable specific db you want
回答3:
Using your example I modified it to accept a string of database names (generated through you crystal reports select action). Then passing this string with the date in question to first validate the database exist and if online add the required union clause to the generated SQL code.
CREATE PROCEDURE TESTSUM
@DbNameS NVARCHAR(max)
,@Date DATETIME
AS
BEGIN
DECLARE @SQL NVARCHAR(MAX) = ''
/* ADD EXTRA ',' RO STRING ARRAY OF DATABASES */
SET @DbNameS = @DbNameS + ',';
DECLARE @L INT = LEN(@DbNameS);
DECLARE @D INT = 0;
DECLARE @LD INT = 1;
DECLARE @DBF VARCHAR(50);
DECLARE @ACTIVE INT = 0;
/* START SQL QUERY */
SET @SQL = 'SELECT SUM([InvoiceSUM]) AS [InvoiceSUM] FROM ( SELECT '''' AS DB, 0.00 AS [InvoiceSUM]' + CHAR(13)
/* LOOP THROUGH EACH DBF NAME PASSED CHECKING IF VALID AND ONLINE */
WHILE @D < @L
BEGIN
SET @D = CHARINDEX(',', @DbNameS,@LD);
IF @LD != @D
BEGIN
SET @DBF = SUBSTRING(@DbNameS,@LD,@D-@LD)
/* VALIDATE DBF IS VALID AND ACTIVE */
SELECT @ACTIVE = COUNT(*) FROM SYS.databases WHERE name = @DBF AND [state] = 0
IF @ACTIVE = 1
BEGIN
/*
BEGIN CODE TO UNION THE SUM RESULTS FOR EACH ACTIVE AND VALID DBF
TO MAKE IT WORK WITH SOME EXISTING DBF's ON MY SYSTEM I CHANGED THE SUMMARY CODE FOR TESTING
*/
SET @SQL = @SQL + 'UNION SELECT '''+ @DBF +''' AS DB, ISNULL(SUM( CAST(DVE AS DECIMAL(18,10)) ),0) AS [InvoiceSUM] FROM '+ @DBF + '.DBO.SO_MSTR WHERE CAST(RecordCreated AS DATE) = '''+ CAST(@Date AS VARCHAR(20)) + '''' + CHAR(13)
END;
END;
SET @LD = @D + 1;
END;
/* CLOSE OUT UNION SUMMARY QUERY */
SET @SQL = @SQL + ') AS DATA'
/* OUTPUT RESULTS */
EXEC SP_EXECUTESQL @SQL
END;
Crystal reports would effective be generating this code: EXEC TESTSUM 'SPA_PROD,SPB_PROD,SPC_PROD','12/09/2014'
来源:https://stackoverflow.com/questions/27408444/sum-up-values-from-databases-and-parametrize-it-sql-server