我有一个存储过程会在我的汇率表中添加货币记录,但我还需要一个相应的列来添加货币。
表结构如下:
CurrencyID CurrencyName Rupee Euro Dollar Pound
----------- ------------ ---------------------- ---------------------- ---------------------- ----------------------
1 Rupee 1 0.008 0.009 0.007
2 Euro 121.3 1 1.08 0.84
3 Dollar 111.4 0.91 1 0.77
4 Pound 143.6 1.18 1.28 1
到目前为止,我的存储过程是这样的:
CREATE PROCEDURE addCurrency
@CurrencyName varchar(30),
@Rupee float,
@Euro float,
@Dollar float,
@Pound float
AS
BEGIN
INSERT into [dbo].[CurrencyTbl] (CurrencyName, Rupee, Euro, Dollar, Pound)
VALUES (@CurrencyName, @Rupee, @Euro, @Dollar, @Pound)
END
BEGIN
DECLARE @SQL VARCHAR(1000)
SELECT @SQL = 'ALTER TABLE [dbo].[CurrencyTbl] ADD ' + @CurrencyName + ' VARCHAR(30)'
END
但是没有创建列
答案 0 :(得分:3)
我认为这不是一个好主意,但你实际上并没有执行你创建的@SQL
,你只是选择它。
您的代码容易受到SQL注入攻击(因为您直接使用连接参数执行sql),所以请小心使用该代码。
另外,如果您要存储数字,为什么数据类型为varchar(30)
?您的其他数据类型为float
(可能应为numeric/decimal
而不是float
。)
你可以这样使用exec sp_executesql @SQL
:
CREATE PROC addCurrency @CurrencyName varchar(30),@Rupee float,
@Euro float,@Dollar float,@Pound float
AS
BEGIN
INSERT into [dbo].[CurrencyTbl] (CurrencyName , Rupee,Euro, Dollar,Pound )
VALUES (@CurrencyName,@Rupee,@Euro,@Dollar,@Pound )
END
BEGIN
Declare @SQL nVarChar(1000)
SELECT @SQL = 'ALTER TABLE [dbo].[CurrencyTbl] ADD ' + @CurrencyName + ' float;'
exec sp_executesql @SQL;
END
动态sql
<小时/> 例如:
/* Monies is the term used by Irkens to refer to their form of currency */
exec addCurrency 'Monies',1,1,1,1
select * from CurrencyTbl
rextester演示:http://rextester.com/CUC99912
返回:
+------------+--------------+------------+----------+----------+----------+--------+
| CurrencyID | CurrencyName | Rupee | Euro | Dollar | Pound | Monies |
+------------+--------------+------------+----------+----------+----------+--------+
| 1 | Rupee | 1,000000 | 0,008000 | 0,009000 | 0,007000 | NULL |
| 2 | Euro | 121,300000 | 1,000000 | 1,080000 | 0,840000 | NULL |
| 3 | Dollar | 111,400000 | 0,910000 | 1,000000 | 0,770000 | NULL |
| 4 | Pound | 143,600000 | 1,180000 | 1,280000 | 1,000000 | NULL |
| 5 | Monies | 1,000000 | 1,000000 | 1,000000 | 1,000000 | NULL |
+------------+--------------+------------+----------+----------+----------+--------+
考虑使用动态sql不需要添加新列和更新列的表的替代表单可能会更好。
这是一个选项:
create table CurrencyTbl (FromCurrencyName varchar(30), ExchangeRate decimal(19,6), ToCurrencyName varchar(30))
insert into CurrencyTbl values
('Rupee ',1.000000,'Rupee')
,('Rupee ',0.008000,'Euro')
,('Rupee ',0.009000,'Dollar')
,('Rupee ',0.007000,'Pound')
,('Euro ',121.300000,'Rupee')
,('Euro ',1.000000,'Euro')
,('Euro ',1.090000,'Dollar')
,('Euro ',0.850000,'Pound')
,('Dollar',111.400000,'Rupee')
,('Dollar',0.910000,'Euro')
,('Dollar',1.000000,'Dollar')
,('Dollar',0.770000,'Pound')
,('Pound ',143.600000,'Rupee')
,('Pound ',1.180000,'Euro')
,('Pound ',1.280000,'Dollar')
,('Pound ',1.000000,'Pound')
你可以像这样动态地转动表格:
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
', ' + quotename(ToCurrencyName)
from CurrencyTbl
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'')
select @sql = '
select FromCurrencyName as CurrencyName,' + @cols + '
from CurrencyTbl
pivot (max([ExchangeRate]) for [ToCurrencyName] in (' + @cols + ') ) p'
exec sp_executesql @sql;
rextester演示:http://rextester.com/EQSC62833
返回:
+--------------+----------+----------+----------+------------+
| CurrencyName | Dollar | Euro | Pound | Rupee |
+--------------+----------+----------+----------+------------+
| Dollar | 1,000000 | 0,910000 | 0,770000 | 111,400000 |
| Euro | 1,090000 | 1,000000 | 0,850000 | 121,300000 |
| Pound | 1,280000 | 1,180000 | 1,000000 | 143,600000 |
| Rupee | 0,009000 | 0,008000 | 0,007000 | 1,000000 |
+--------------+----------+----------+----------+------------+
答案 1 :(得分:1)
我创建了临时表,但这也应该与标准表一起使用......
CREATE TABLE #Currencies (
Currencyid INTEGER identity(1, 1) PRIMARY KEY
,CurrencyName VARCHAR(255)
)
CREATE TABLE #ConversionRates (
CurrencyId1 INTEGER
,CurrencyId2 INTEGER
,Conversion1To2Rate DECIMAL(19, 6)
)
然后我们有一个存储过程来处理工作
/************************************************************************************************
Stored Procedure: dbo.usp_AddCurrency
M. Jay Wheeler -- mjwheele@yahoo.com
****************************************************************************************************/
CREATE PROCEDURE [dbo].usp_AddCurrency --
@CurrencyName VARCHAR(255) = NULL
,@CurrencyId INTEGER = NULL
,@Currency2Id INTEGER = NULL
,@Currency1ToCurrency2ExchangeRate DECIMAL(19, 6) = NULL
AS
BEGIN
DECLARE @ErrorMessage VARCHAR(MAX) = ''
DECLARE @ThrowErrorOnAddingAlreadyExists CHAR(1) = 'N' -- If N will automatically update the currency Name.
BEGIN TRY
--#############################################################################
-- Check Parameters
--#############################################################################
IF @CurrencyId IS NULL
AND @CurrencyName IS NULL
SELECT @ErrorMessage += '@CurrencyID and @CurrencyName cannot both be null.' + CHAR(13)
IF @CurrencyId IS NULL
AND NOT EXISTS (
SELECT 1
FROM #Currencies
WHERE CurrencyName = @CurrencyName
)
BEGIN
INSERT INTO #Currencies (CurrencyName)
SELECT @CurrencyName
SELECT @CurrencyId = SCOPE_IDENTITY()
END
SELECT @CurrencyId = CurrencyId
FROM #Currencies
WHERE CurrencyName = @CurrencyName
AND @CurrencyId IS NULL
SELECT @CurrencyName = CurrencyName
FROM #Currencies
WHERE Currencyid = @CurrencyId
AND @CurrencyName IS NULL
IF NOT EXISTS (
SELECT 1
FROM #Currencies
WHERE Currencyid = @CurrencyId
)
SELECT @ErrorMessage += '@CurrencyID: ' + isnull(Cast(@CurrencyId AS VARCHAR(15)), 'NULL') + ' Does Not Exist.' + CHAR(13)
IF EXISTS (
SELECT 1
FROM #Currencies c
WHERE c.Currencyid <> @CurrencyId
AND c.CurrencyName = @CurrencyName
)
SELECT @ErrorMessage += 'Currency: ' + @CurrencyName + ' already exists with an ID of ' + cast((
SELECT currencyId
FROM #Currencies
WHERE CurrencyName = @CurrencyName
) AS VARCHAR(15)) + CHAR(13)
IF EXISTS (
SELECT 1
FROM #Currencies c
WHERE c.Currencyid = @CurrencyId
AND c.CurrencyName <> @CurrencyName
)
UPDATE #Currencies
SET CurrencyName = @CurrencyName
WHERE Currencyid = @CurrencyId
IF @Currency2Id IS NOT NULL
AND @Currency1ToCurrency2ExchangeRate IS NULL
SELECT @Errormessage += 'Improper Syntax no exchange rate to assignmen.' + CHAR(13)
IF @Currency2id IS NULL
AND @Currency1ToCurrency2ExchangeRate IS NOT NULL
SELECT @Errormessage += 'Improper Syntax no "To Currency" for rate assignment.' + CHAR(13)
IF len(@ErrorMessage) > 0
RAISERROR ('%s' ,16 ,1 ,@ErrorMessage)
--#############################################################################
-- you get the idea more error checking needed to bullet proof. Now assume
-- We have all the correct Parameters set up, we've made sure anything coming in
-- needs to be added or updated by this point.
--#############################################################################
--#############################################################################
-- nothing to do if @Currency2Id is null
--#############################################################################
IF @Currency2Id IS NULL
RETURN
--#############################################################################
-- see if we need to add/Update a conversion rate.
--#############################################################################
UPDATE #ConversionRates
SET Conversion1To2Rate = @Currency1ToCurrency2ExchangeRate
WHERE @CurrencyId = CurrencyId1
AND @Currency2Id = CurrencyId2
INSERT INTO #ConversionRates (
CurrencyId1
,CurrencyId2
,Conversion1To2Rate
)
SELECT @CurrencyId
,@Currency2Id
,@Currency1ToCurrency2ExchangeRate
WHERE NOT EXISTS (
SELECT 1
FROM #ConversionRates
WHERE @CurrencyId = CurrencyId1
AND @Currency2Id = CurrencyId2
)
END TRY
BEGIN CATCH
IF @@Trancount > 0
ROLLBACK TRAN
DECLARE @ErrorBlockLineLen INTEGER = 0
DECLARE @ErrorBlockGotTheFormat BIT = 0
DECLARE @ErrorFormatIndent INTEGER = 3
DECLARE @ErrorBlockBeenThrough INTEGER = NULL -- must be set to null
DECLARE @ThisProcedureName VARCHAR(255) = ISNULL(OBJECT_NAME(@@PROCID), 'Testing')
DECLARE @ErrorProc VARCHAR(4000) = CONVERT(VARCHAR(4000), ISNULL(ERROR_PROCEDURE(), @ThisProcedureName))
WHILE @ErrorBlockGotTheFormat = 0
BEGIN
IF @ErrorBlockBeenThrough IS NOT NULL
SELECT @ErrorBlockGotTheFormat = 1
SET @errormessage = Space(isnull(@ErrorFormatIndent, 0)) + @ThisProcedureName + ' Reports Error Thrown by: ' + @ErrorProc + CHAR(13)
SET @errormessage += Space(isnull(@ErrorFormatIndent, 0)) + '-------->' + ISNULL(CONVERT(VARCHAR(4000), ERROR_MESSAGE()), 'Unknown') + '<--------' + CHAR(13) -- + Space(isnull(@ErrorFormatIndent,0)) + REPLICATE('=', @ErrorBlockLineLen) + CHAR(13) -- + Space(isnull(@ErrorFormatIndent,0)) + UPPER(@ThisProcedureName + ' Variable dump:') + CHAR(13) -- + Space(isnull(@ErrorFormatIndent,0)) + REPLICATE('=', @ErrorBlockLineLen) + CHAR(13) --
+ CHAR(13) + Space(isnull(@ErrorFormatIndent, 0)) + '@Currency1ToCurrency2ExchangeRate:.....<' + ISNULL(CAST(@Currency1ToCurrency2ExchangeRate AS VARCHAR(25)), 'Null') + '>' + CHAR(13) + SPACE(ISNULL(@ErrorBlockBeenThrough, 0)) --
+ CHAR(13) + Space(isnull(@ErrorFormatIndent, 0)) + '@Currency2Id:..........................<' + ISNULL(CAST(@Currency2Id AS VARCHAR(25)), 'Null') + '>' + CHAR(13) + SPACE(ISNULL(@ErrorBlockBeenThrough, 0)) --
+ CHAR(13) + Space(isnull(@ErrorFormatIndent, 0)) + '@CurrencyId:...........................<' + ISNULL(CAST(@CurrencyId AS VARCHAR(25)), 'Null') + '>' + CHAR(13) + SPACE(ISNULL(@ErrorBlockBeenThrough, 0)) --
+ CHAR(13) + Space(isnull(@ErrorFormatIndent, 0)) + '@CurrencyName:.........................<' + ISNULL(CAST(@CurrencyName AS VARCHAR(25)), 'Null') + '>' + CHAR(13) + SPACE(ISNULL(@ErrorBlockBeenThrough, 0)) --
--SELECT @ErrorBlockLineLen = MAX(LEN(RTRIM(item)))
--FROM dbo.fnSplit(@errormessage, CHAR(13))
SELECT @ErrorBlockLineLen = 120
SELECT @ErrorBlockBeenThrough = 1
END
RAISERROR ('%s' ,16 ,1 ,@ErrorMessage)
END CATCH
END
GO
这是填充的代码。我使用了一些比率的倒数,因为它更容易。
set nocount on
exec usp_AddCurrency 'Rupiee'
exec usp_AddCurrency 'Euro'
exec usp_AddCurrency 'Dollar'
exec usp_AddCurrency 'Pound'
exec usp_AddCurrency "Rupiee", Null, 1, 1.000000
exec usp_AddCurrency "Rupiee", Null, 2, 0.008000
exec usp_AddCurrency "Rupiee", Null, 3, 0.009000
exec usp_AddCurrency "Rupiee", Null, 4, 0.007000
Declare @Inverse Decimal(19,6)
Select @Inverse = cast ((1.000000/ (Select Conversion1To2Rate From #ConversionRates Where CurrencyId1 = 1 and CurrencyId2 =2 )) as decimal(19,6))
exec usp_AddCurrency 'Euro' , Null, 1, @Inverse
exec usp_AddCurrency 'Euro' , Null, 2, 1.000000
exec usp_AddCurrency 'Euro' , Null, 3, 1.090000
exec usp_AddCurrency 'Euro' , Null, 4, 0.850000
Select @Inverse = cast ((1.000000/ (Select Conversion1To2Rate From #ConversionRates Where CurrencyId1 = 1 and CurrencyId2 =3 )) as decimal(19,6))
exec usp_AddCurrency 'Dollar' , Null, 1,@Inverse
Select @Inverse = cast ((1.000000/ (Select Conversion1To2Rate From #ConversionRates Where CurrencyId1 = 2 and CurrencyId2 =3 )) as decimal(19,6))
exec usp_AddCurrency 'Dollar' , Null, 2, @Inverse
exec usp_AddCurrency 'Dollar' , Null, 3, 1.000000
exec usp_AddCurrency 'Dollar' , Null, 4, 0.770000
Select @Inverse = cast ((1.000000/ (Select Conversion1To2Rate From #ConversionRates Where CurrencyId1 = 1 and CurrencyId2 =4 )) as decimal(19,6))
exec usp_AddCurrency 'Pound' , Null, 1, @Inverse
Select @Inverse = cast ((1.000000/ (Select Conversion1To2Rate From #ConversionRates Where CurrencyId1 = 2 and CurrencyId2 =4 )) as decimal(19,6))
exec usp_AddCurrency 'Pound' , Null, 2, @Inverse
Select @Inverse = cast ((1.000000/ (Select Conversion1To2Rate From #ConversionRates Where CurrencyId1 = 3 and CurrencyId2 =4 )) as decimal(19,6))
exec usp_AddCurrency 'Pound' , Null, 3, @Inverse
exec usp_AddCurrency 'Pound' , Null, 4, 1.000000
我认为这是你问题的结束。 我用这段代码测试了输出:
Declare @MySQL nVarChar(max) = 'Create Table ##output ([Currency Name] Varchar(255),' + char(13)
SELECT @MySQL += STUFF(( SELECT ',[' + CurrencyName + '] VARCHAR(255) '
FROM #Currencies
order by Currencyid asc
FOR
XML PATH('')
), 1, 1, '') + ')'
exec sp_executesql @MySQL
select * into #output from ##output
Drop Table ##Output
Declare @PivotThings varchar(max)
select @PivotThings = STUFF(( SELECT ',[' + CurrencyName + '] '
FROM #Currencies
order by Currencyid asc
FOR
XML PATH('')
), 1, 1, '')
Select @MySQL = '
SELECT *
FROM(
select c1.CurrencyName as Rows, c1.Currencyid as r, c2.CurrencyName as Cols, Conversion1To2Rate as [Value] from #ConversionRates r
join #Currencies c1 on c1.Currencyid = r.CurrencyId1
join #Currencies c2 on c2.Currencyid = r.CurrencyId2
) WorkOrders
PIVOT
(
SUM(value)
FOR [cols] IN (
##PivotThings##
)
) AS PivotTable
ORDER BY [r]
'
Select @MySQL = REPLACE(@mysql , '##PivotThings##', @pivotthings)
exec sp_executesql @mysql
希望你觉得这很有用。这是我的第一篇文章evah!