以下代碼在 C# Winforms 中執行。我要做的是在程式啟動時創建表和存盤程序。我IF NOT EXISTS在我的 SQL 命令中使用。如果不存在,則創建,否則什么也不做。
創建表格沒問題,效果很好。
但是在創建存盤程序時,Visual Studio 會拋出這個錯誤;
必須宣告標量變數@xxxx
在收到此錯誤之前,我正在使用USE和GO命令,這種方法也給出了CREATE/ALTER PROCEDURE錯誤。隨著我在網路上的研究,我逐漸了解到這一點,USE并且GO在 C# 中是一個禁忌。這就是為什么我使用Else而不是GOafter IF NOT EXISTS。
該代碼在 T-SQL 中作業,但我想我需要以某種方式將其轉換為 C#。
任何幫助表示贊賞。謝謝。
更新:
在我將 StringBuilder 更改為 just 字串后,它修復了之前的錯誤。現在它給出了下面的一個。雖然找不到任何不妥之處。
" System.Data.SqlClient.SqlException
HResult=0x80131904
Message=Incorrect Syntax near the 'Trendyol'.
Unclosed quotation mark after the character string "', ')))))AS varchar) FROM urnBilgi INNER JOIN urn ON urn.stkID = bVeriID WHERE bVeriID = @stkID and bBilgiID = @bBilgiID AND(urn.fiyatS BETWEEN @fiyat_baslangic and @fiyat_bitis) END END'"
public void createSP()
{
StringBuilder sbSP = new StringBuilder();
sbSP.AppendLine(" IF NOT EXISTS(SELECT * FROM sys.objects WHERE type = 'P' AND object_id = object_id('etradeCore'))"
" exec('CREATE PROCEDURE [dbo].[etradeCore]("
" ELSE" //Used Instead of GO
" ALTER PROCEDURE [dbo].[etradeCore]("
" @pazaryeri VARCHAR(50),"
" @magaza VARCHAR(50),"
" @stkID int,"
" @komisyon decimal(9, 4),"
" @fiyat_baslangic decimal(9, 4),"
" @fiyat_bitis decimal(9, 4),"
" @eklenecekfiyat decimal(9, 4)"
")"
" AS BEGIN"
" SET NOCOUNT OFF"
" SET ANSI_NULLS ON"
" SET QUOTED_IDENTIFIER ON"
" DECLARE @bBilgiID tinyint"
" IF(@pazaryeri = 'Trendyol' and @magaza = 'Kozmeti')"
" SET @bBilgiID = 58"
" ELSE IF(@pazaryeri = 'Trendyol' and @magaza = 'Golden Rose')"
" SET @bBilgiID = 52"
" ELSE IF(@pazaryeri = 'Trendyol' and @magaza = 'Ziaja')"
" SET @bBilgiID = 60"
" ELSE IF(@pazaryeri = 'Hepsiburada' and @magaza = 'Kozmeti')"
" SET @bBilgiID = 43"
" ELSE IF(@pazaryeri = 'Hepsiburada' and @magaza = 'Golden Rose')"
" SET @bBilgiID = 44"
" ELSE IF(@pazaryeri = 'Hepsiburada' and @magaza = 'Ziaja')"
" SET @bBilgiID = 43"
" IF NOT EXISTS(select * from urnBilgi WHERE bVeriID = @stkID and bBilgiID = @bBilgiID and bDeger >= convert(varchar, 0))"
" BEGIN"
" INSERT INTO urnBilgi(bVeriID, bBilgiID, bDeger) VALUES(@stkID, @bBilgiID, '0')"
" END"
" ELSE"
" BEGIN"
" UPDATE urnBilgi SET bDeger ="
" CAST(CONVERT(decimal(9, 4), ((((Select fiyatS from urn where stkID = @stkID) @eklenecekfiyat)) *"
" CONVERT(decimal(9, 4), convert(varchar, '1.' REPLACE(@komisyon, '.', ''))) ))AS varchar)"
" FROM urnBilgi"
" INNER JOIN"
" urn ON urn.stkID = bVeriID"
" WHERE bVeriID = @stkID and bBilgiID = @bBilgiID AND(urn.fiyatS BETWEEN @fiyat_baslangic and @fiyat_bitis)"
" END"
" END"
);
using (SqlConnection connection = new SqlConnection(constring))
{
using (SqlCommand cmd = new SqlCommand(sbSP.ToString(), connection))
{
connection.Open();
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
connection.Close();
}
}
}
uj5u.com熱心網友回復:
您不能GO在 SQL 批處理中使用SqlCommand. 它不是有效的 T-SQL,它只是 sqlcmd 和 SSMS 使用的批處理分隔符。
相反,您需要使用新命令拆分批次。
但是在這個特定的例子中,您實際上并不需要兩個命令。首先是因為您可以使用CREATE OR ALTER PROCEDURE. 其次,即使您確實需要,因為您只是通過動態 SQL 執行此操作,您可以有條件地構建一個動態 SQL 腳本以通過。
您也可以洗掉StringBuilder并改用逐字@""字串。這允許您插入換行符并充分利用空格。
當前腳本的另一個問題是您沒有'為動態 SQL 轉義。像我所做的那樣將它作為引數傳遞可以避免這種情況,但是如果您想在一個大批量中完成所有操作,則需要確保這樣做。
public void createSP()
{
const string sqlExec = @"
IF NOT EXISTS (SELECT 1
FROM sys.procedures
WHERE name = 'etradeCore')
exec(@sql);
";
const string sbSP = @"
CREATE OR ALTER PROCEDURE [dbo].[etradeCore]
@pazaryeri VARCHAR(50),
@magaza VARCHAR(50),
@stkID int,
@komisyon decimal(9, 4),
@fiyat_baslangic decimal(9, 4),
@fiyat_bitis decimal(9, 4),
@eklenecekfiyat decimal(9, 4)
AS
SET NOCOUNT OFF;
DECLARE @bBilgiID tinyint =
CASE @pazaryeri
WHEN 'Trendyol'
THEN
CASE @magaza
WHEN 'Kozmeti'
THEN 58
WHEN 'Golden Rose'
THEN 52
WHEN 'Ziaja'
THEN 60
END
WHEN 'Hepsiburada'
THEN
CASE @magaza
WHEN 'Kozmeti'
THEN 43
WHEN 'Golden Rose'
THEN 44
WHEN 'Ziaja'
THEN 43
END
END;
IF NOT EXISTS (SELECT 1
FROM urnBilgi
WHERE bVeriID = @stkID
AND bBilgiID = @bBilgiID
AND bDeger >= '0')
BEGIN
INSERT INTO urnBilgi (bVeriID, bBilgiID, bDeger)
VALUES (@stkID, @bBilgiID, '0');
END
ELSE
BEGIN
UPDATE b
SET bDeger = CAST(
CONVERT(decimal(9, 4),
(
u.fiyatS @eklenecekfiyat
) * CONVERT(decimal(9, 4), '1.' REPLACE(@komisyon, '.', ''))
) AS varchar(30))
FROM urnBilgi b
INNER JOIN urn u ON u.stkID = b.bVeriID
WHERE b.bVeriID = @stkID
AND b.bBilgiID = @bBilgiID
AND (u.fiyatS BETWEEN @fiyat_baslangic AND @fiyat_bitis);
END
";
using (SqlConnection connection = new SqlConnection(constring))
using (SqlCommand cmd = new SqlCommand(sqlExec, connection))
{
cmd.Parameters.Add("@sql", SqlDbType.NVarChar, -1).Value = sbSP;
connection.Open();
cmd.ExecuteNonQuery();
}
}
筆記:
SET ANSI_NULLS ONSET QUOTED_IDENTIFIER ON應該是連接字串設定的一部分,而不是批處理的一部分- 使用
sys.procedures代替sys.objects - 使用
EXISTS (SELECT 1代替EXISTS (SELECT * - 目前尚不清楚為什么您將
@komisyon作為小數傳遞只是為了洗掉.也許您應該通過 anint或其他方式。 - 總是
varchar用長度宣告。 - 為什么是
bDeger無論如何varchar?不應該decimal嗎? - 不清楚為什么你需要內部
SELECT fiyatS...子查詢UPDATE而不只是u.fiyatS. CommandType.Text是默認值。Close()如果您有障礙,則無需致電using(應該如此)。- 為什么是
SET NOCOUNT OFF?通常最好讓它保持打開狀態。 - 整個“upsert”程序可能應該在一個事務中,帶有
HOLDLOCK提示,并且可能應該@@ROWCOUNT用于檢查。
uj5u.com熱心網友回復:
Caius Jard的評論暫時還可以。即使真正的問題沒有解決,我還是跳過了程式的下一步。
如果您從 c# 運行,則無需檢查存盤程序的存在;如果 proc 存在,則創建它的嘗試將失敗,并且 c# 將遇到可以忽略的例外。把事情簡單化
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/469058.html
上一篇:VisualStudio2022 XamariniOS應用程式-無法在Mac/連接的iPhone上啟動應用程式
下一篇:在張量中找到使值總和最大化的樞軸
