1.変数
SQLステートメントを動的に作成するには、変数があってはなりません。
変数を宣言し、値を割り当てます。
declare @i as int;--定义一个 int 类型的 变量 (as可以省略)
print @i;--这注意:没有赋值之前,程序不会报错,而且输出一个 空
set @i=3;
print @i;
SQL Server 2008以降、宣言しながら変数に値を割り当てることができます
declare @a int=3;
print @a;
変数を使用する過程で、nvarcahrとncharの違いに注意を払う必要があります。
declare @s nvarchar(20);
set @s='Hello';
set @s=@s+' World!';
print @s;--输出的是 Hello World!
declare @s2 nchar(20);
set @s2='Hello';
set @s2=@s2+' World!';
print @s2;--输出的是 Hello。
ncharがHelloを出力するのはなぜですか?ncharは固定長であるため、長さが最大に達していない場合でも、残りの長さは空に置き換えられるため、fullと同等であるため、文字列の追加は機能しません。
クエリで値を割り当てます:
declare @now datetime;
select @now=GETDATE();
print @now;
declare @orderNum int;
select @orderNum = COUNT(1) from [Sales.Orders];--这条查询语句只是用来 对 变量进行赋值的,不会返回查询结果的.
print @orderNum;
主な機能:次の用途のために、クエリ結果を変数に保存します。
実際、セット割り当てを使用して上記の効果を実現することもできます
set @orderNum =(select COUNT(1) from [Sales.Orders])
print @orderNum
2.バッチ処理
「go」を使用すると、goの前のすべてのステートメントが1つのバッチになります。異なるバッチの変数を相互に呼び出すことはできません。
3.プロセス制御
1)状態制御
declare @minute int ;
set @minute =DATEPART(minute,getdate());
if @minute>20
begin--一条语句可以将 begin end 省略
print '马上睡觉';
end
else
print '继续快乐玩耍';
2)ループ制御
--高斯问题
declare @sum int,@i int;
set @sum=0;
set @i=0;
while @i<100
begin
set @i=@i+1;
set @sum=@sum+@i;
end
print @sum;
SQL Serverでのcontinueとbreakの使用は、c#の場合と同じです。
4.カーソル
カーソルとは:
コレクションの操作に基づくものではありませんが、コレクション内のデータを1つずつ取り出し、1つずつ操作を行います。
カーソルを使用する場合:
デフォルトでは、コレクションメソッドを使用してクエリを実行します。カーソルを使用する場合は、説得力のある理由で使用することを検討する必要があります。
カーソルを使用しない理由:
1.カーソルの使用は、設定された考慮事項に基づくリレーショナルモデルに重大な違反をします。
2.レコードを1つずつ操作すると、パフォーマンスのオーバーヘッドが発生します。コレクションが与えられた場合、コレクションに対して一連のカーソルコード操作を実行すると、パフォーマンスのオーバーヘッドが確実に発生し、このカーソルの使用方法のパフォーマンスはコレクションの数倍遅くなります。
3.カーソルを使用するには多くのコードが必要です。ただし、コレクションを使用する場合は、必要なデータのみをクエリし、取得方法を説明しません。カーソルで記述されたコードの多くは、読みにくく、保守も不十分です。
存在の意味:
多くの欠点を述べてきましたが、カーソルには意味がありますか?もちろん、クエリされたデータを1つずつ処理する必要がある場合は、カーソルを使用する必要があります。
カーソルを使用する手順:
1.クエリでカーソルを宣言します
2.カーソルを開きます
3.最初の値から始まる対応する変数に値を割り当てます。
4.カーソルをループし、割り当てられた変数を使用して操作します。
5.カーソルを閉じます
6、カーソルを離します
--1、首先在查询基础上声明游标
declare c cursor
for
select shipperid,companyname
from [Sales.Shippers];
--2、打开游标
open c;
--3、从第一个游标开始把 值 赋值到 对应的变量里面
declare @id int,@name nvarchar(20);
--每次取出来一条数据, 添加到指定的 变量。
fetch next from c into @id,@name;
--4、循环遍历 游标,将赋值的变量 拿过来进行相应的操作
while @@FETCH_STATUS=0--等于0代表 游标没有超过最后一行
begin
--相应的操作处理
print @name;
--尝试 读取下一条 数据
fetch next from c into @id,@name;
end
--5、关闭游标
close c;
--6、释放游标
deallocate c;
総括する:
1.カーソルを使用します。パフォーマンスの消費が非常に大きいため、非常に注意してください。不確かな場合は絶対に使用できません。
2.カーソルの唯一の利点は、クエリデータに対して1つずつ操作を実行できることです。これはまさにそれが適応するところです。
5.一時テーブル
使用するシーン:
一部のデータをテーブルに保存したいが、データテーブルを作成したくない場合(一般的な会社にはテーブルを作成するためのDBAしかないため)、または現在のデータを現在のセッションでのみ表示するように指示します、または現在のバッチが表示されている限り。
一時テーブルのタイプ:
SQL Server 3種類の一時テーブル:ローカル一時テーブル、グローバル一時テーブル、テーブル変数
以下では、3種類の一時テーブルについて個別に説明します。
ローカル一時テーブル:
1.作成プロセスと使用法は通常のテーブルと同じであり、「#」は一時テーブルを意味します。
2.彼を作成したセッションにのみ表示され、システムデータベースのtempdbデータの一時テーブルに保存されます。現在のセッション(プロセス)が終了すると、一時テーブルは自動的に削除されます
3. SQL Serverのシステムによって作成された一時テーブルには、異なるプロセス間で同じテーブル名が作成されないようにし、一意性を確保するために接尾辞が付けられます。
一時テーブルを作成する通常の方法:
create table #partTable
(
num int
);
insert into #partTable (num) values (1),(2),(3);
go;--不再 一个 批 里面 也能使用 ,只要是在同一个 进程里面
select * from #partTable;
クエリ中に一時テーブルを作成し、クエリデータを一時テーブルに挿入します
select * into #table from [Sales.Shippers]
select * from #table;
グローバル一時テーブル:
1.グローバル一時テーブルを表すために、テーブル名の前に2つの「#」を追加します
2.注:すべてのセッション(プロセス)に表示されますが、現在のプロセスが閉じられているか、グローバル一時テーブルが長期間使用されていない場合は削除されます
create table ##allTable
(
num int
);
insert into ##allTable (num) values(1),(2),(3),(4);
select * from ##allTable
テーブル変数:
注:tempdbデータベースに対応する物理一時テーブルも作成されますが、現在の操作の「バッチ」にのみ表示され、一時テーブルは現在のバッチの実行後に削除されます(したがって、必ず注:テーブル変数はメモリに保存されません。彼は物理データテーブルも作成します)
パフォーマンスに関する考慮事項:データの行が数行しかない場合は、もちろんテーブル変数のパフォーマンスは良好ですが、データ量が多い場合は、一時テーブルを使用する必要があります。
declare @tableVariable table
(
num int
)
insert into @tableVariable (num) values (1),(2),(3);
select * from @tableVariable;
go;
--不再同一 批 里面是不能访问到 表 变量
select * from @tableVariable;
最も重要な点:テーブル変数は変数と同じです。トランザクションがロールバックされると、変数の値はロールバックされません。同様に、テーブル変数はロールバックされません。
--回滚中 变量的不会回滚的 特殊情况
declare @num int;
set @num =1;
begin transaction;
set @num=12;
print @num;
rollback;
--注意:事务回滚,如果变量在 事务里面 改变,回滚的时候 变量是不会回滚的.
print @num;
--同理:表变量也是如此的
declare @tableVariable2 table
(
num int
);
insert into @tableVariable2 (num) values(1),(2),(3);
begin transaction;
delete from @tableVariable2 where num =1;
rollback;
--表变量是不会 回滚的
select * from @tableVariable2;
6、動的SQL
動的SQLとは
まず第一に、静的SQLは通常の静的クエリステートメントです。
動的SQL:execを使用して文字列SQLステートメントを実行します。
declare @sql nvarchar(100);
set @sql ='select * from [Sales.Shippers]';
exec(@sql)
短所:SQLインジェクションの脆弱性攻撃を防ぐことはできません。(誰もがSQLインジェクションの脆弱性が何であるかを知っている必要があります。私はそれを紹介しません)
上記のSQLインジェクションの脆弱性攻撃を解決するために、2番目の動的SQLがあります。sp_executesqlストアドプロシージャ:
1.入力パラメータと出力パラメータの設定をサポートしているため安全です
2.パフォーマンスはexecよりも優れています:そのパラメーター化はキャッシュされた実行プランの再利用に役立つためです。実行プラン:SQLサーバーがSQLステートメントを処理するときに生成される命令です。キャッシュ内の実行プランを再利用する場合は、sqlを確認する必要があります。文字列ステートメントは同じです。したがって、パラメーター化されたsqlステートメントはパラメーターを置き換えるだけでよいため、sqlステートメントは変更せずに再利用できます。
declare @sql nvarchar(100);
set @sql='select * from [Sales.Shippers] where companyname=@name';
declare @name nvarchar(20);
--set @name='顺丰';
set @name='顺丰;select * from [Sales.Shippers]';--即使这样,想要进行sql 注入漏洞攻击,不可能,因为 在sql 语句 把整个 @name里面的 值 作为一个 字符串 来使用的,就是执行 companyname 和 整个字符串的对比
exec sp_executesql
--下面两个是非常重要的
@stmt=@sql,--动态执行的 sql语句
@params=N'@name as nvarchar(20)',--参数的类型
@name=@name;--参数赋值
7.ルーチン
ルーチンは何ですか:
結果を計算したり、タスクを実行したりするためにカプセル化されたコードのプログラミング現象。ルーチンに関してはわからないかもしれませんが、次の3つのタイプについて言及すると、すべてを知っています。
ルーチンの種類:
ユーザー定義関数、ストアドプロシージャ、トリガー
最も一般的に使用されるのはストアドプロシージャです。以下では、最初にストアドプロシージャを紹介します。
ストアドプロシージャ:
ストアドプロシージャを作成します。
--存储过程:最常用的方法
create procedure MyDemoPro
(
--存储过程中 要使用到 的参数
@orderid int
)
as
--下面是执行的 sql 语句
select * from [Sales.Orders] where orderid=@orderid;
ストアドプロシージャを実行します。
exec MyDemoPro @orderid=10;
--可以简写成:exec MyDemoPro 10;
ストアドプロシージャを理解するには、その3つのパラメータタイプを理解する必要があります。
着信パラメータ、発信パラメータ、戻りパラメータ。
着信パラメータ:
これは通常のパラメータです。上記で使用されているのはパラメータです。
発信パラメータ:
出力によって定義されたパラメーター:ユーザーが使用できるように送信できます
create procedure OrderCount
(
@count int output
)
as
select @count=COUNT(*) from [Sales.Orders];
go;
--执行 ,一定以声明一个变量 ,赋值给 传出参数
declare @outCount int ;
exec OrderCount @count=@outCount output;
print @outCount;
戻りパラメータ:
特別なパラメータ:c#とは異なり、ここでは操作結果の正しさまたはエラーを示すためにのみ使用され、数値のみを返すことができます
alter procedure ReturnProc
(
@username nvarchar(100)
)
as
declare @usernameLen int;
set @usernameLen=LEN(@username);
if @usernameLen>=5
return '1';
else
return '0';
declare @result int;
--如何为 return 参数 赋值
exec @result = ReturnProc @username='wanglihong';
print @result;
戻りパラメーターを「asd」に設定すると、エラーが次のように報告されます。
カスタム機能:
1.値を直接返すことができます
2.2つのタイプがあります。
スカラー関数(戻り値は値です)
テーブル関数(戻り値はテーブルです)(プログラマビリティの関数に存在します)
3.実際の開発ではめったに使用されません。
create function GetMinute
(
@date datetime
)
--设置返回值:
returns int
as
begin
declare @minute int;
set @minute =datepart(minute,@date);
return @minute;
end
--使用自定义函数
select dbo.GetMinute(GETDATE());
引き金:
特別なストアドプロシージャ。主な役割:検索。注:トリガーはイベントにアタッチする必要があります。イベントが発生した場合にのみ、トリガーが起動され、トリガーコードが実行されます。(SQL Serverには、トリガーに対応する2つのイベントがあります。データ操作イベントとデータ定義イベントです。これらは次のトリガーに対応します)
2つのタイプがあります:
DMLトリガー(変更トリガー:テーブルデータの変更:更新など)
DLLトリガー(アーキテクチャトリガー:データベースアーキテクチャの変更:テーブルの作成など)
DMLトリガー:
2つのタイプがあります:
1.トリガー後(テーブル上で操作)
2.トリガーの代わりに(ビューを操作)
注:トリガーコードでは、挿入と削除の2つのテーブルにのみアクセスできます。データの更新は、最初に削除されてから挿入されます。挿入されたテーブルには、挿入および更新操作後の新しいデータの行が含まれています。削除されたテーブルには、削除および更新操作後の古いデータの行が含まれています。
アフタートリガーがよく使用されるため、ここではアフターの概要のみを示します。
afterトリガーは、それに関連付けられたイベントが実行された後に起動されます。
配送業者(配送会社)テーブルのログテーブルを作成します。
create table Ship_Log
(
id int identity(1,1) primary key,
op_date datetime default getdate(),
op_uaer nvarchar(50),
op nvarchar(50),
shipname nvarchar(50),
shipphone nvarchar(50)
)
テーブルdbo.Sales.Shipperのトリガーを作成します
create trigger ship_log_trigger
on [Sales.Shippers] after insert
as
--当对上面的表进行 增删改的时候执行 触发器的下面的代码
insert into Ship_Log (op_uaer,op,shipname,shipphone)
select user_name()--返回当前操作的用户名
,'insert',companyname,phone from inserted;
テーブルdbo.Sales.Shipperにデータを挿入して、トリガーをトリガーします。
insert into [Sales.Shippers] (companyname,phone) values('shits','12345678')
クエリログテーブル:
select * from Ship_Log;
検索結果:
ログが挿入されました。
DLLトリガー
通常は使用されません。
2つのタイプがあります:
データベースでトリガーします(例:テーブルを作成します)
サーバーへのトリガー(例:データベースの作成)
8.識別
識別:場合によっては、主キーを識別列に設定し(列を自動的に増やします)、識別を照会すると、新しく追加された識別列の値が見つかります。
2つのタイプがあります:
1.グローバルスコープ:@@ identity
2.現在のテーブルのスコープ:SCOPE_IDENTITY();最も一般的に使用されます
注:トリガーを含むテーブルにデータを挿入する場合、クエリの結果は異なります(テーブルにデータを挿入した後、トリガーはログテーブルにもデータを挿入するため、見つかったグローバル識別子はログテーブルの識別子、およびSCOPE_IDENTITY()によって検出されたデータテーブルの識別子
insert into [Sales.Shippers] (companyname,phone) values('asd','12345');
select @@identity;--整个数据库中所有的 最新最新增加的 标识列
select SCOPE_IDENTITY();--获得 当前操作的表的最新增加的 标识列的值
トリガーなしでテーブルにデータを挿入する場合、2つのクエリID列の値は同じです