OpenQuery 可
---
當資料是需要彈性Server時
```sql=
DECLARE @StrStartDate VARCHAR(20),
@sqlCommand varchar(MAX)
SET @StrStartDate = CONVERT(varchar(20), @StartDt, 120)
SET @sqlCommand = 'SELECT cg.GroupID, cg.GroupName
FROM [OBDataCenter].[dbo].[CCRGroup] cg (NOLOCK)
WHERE cg.CreateDate >= '''''+ @StrStartDate +'''''
AND cg.DisableFlag = ''''0''''
AND cg.ProjectID = '''''+ @ProjectID + ''''''
SET @sqlCommand = 'SELECT * FROM OPENQUERY(['+ @Server +'],'''+ @sqlCommand +''')'
EXEC(@sqlCommand)
```
逐筆更新
---
當要更新的表單很常被Query,但同時又要更新大筆資料時,除了NOLOCK,也可以用迴圈逐筆更新,Query才不會太慢
```sql=
CREATE TABLE #tmpTable(
Column1 INT,
Column2 VARCHAR(40),
RowsNum INT IDENTITY(1,1)
)
CREATE INDEX IDX_tmpTable_RowsNum ON #tmpTable(Column1, Column2, RowsNum)
-- 迴圈宣告
DECLARE @rc INT;
DECLARE @tableRows INT;
DECLARE @batchSize INT;
DECLARE @start INT;
DECLARE @end INT;
-- 預設每次更新筆數
SET @batchSize = 1000;
-- 資料總筆數
SELECT @tableRows = (MAX(tcc.RowsNum) + 1) FROM #tmpTable tcc;
SET @rc = 1;
SET @start = 1;
SET @end = @start + @batchSize - 1;
WHILE @rc < @tableRows
BEGIN
UPDATE cr
SET
Column4 = '123',
Column4 = '456',
FROM #tmpTable tcci
JOIN DemoTable cr (NOLOCK) ON cr.Column1 = @Column1
AND cr.Column1 = tcci.Column1
AND cr.Column2 = tcci.Column2
WHERE tcci.RowsNum BETWEEN @start AND @end
SET @rc += @batchSize;
SET @start = @end + 1;
SET @end = @start + @batchSize - 1;
END
```
新舊資料比對(檢查)
---
```sql=
-- 1.先放至temp表單中
IF OBJECT_ID('tempdb..#tmpProject') IS NOT NULL DROP TABLE #tmpProject
SELECT 'Project' AS TableName,p.ProjectGUID, p.SystemGUID, p.ProjectName,
p.ImportID, p.[Server], p.DBName, p.CreateDate, p.Creator,
p.MaintainDate, p.Maintainer, p.[Status]
INTO #tmpProject
FROM [dbo].[Project] p(NOLOCK)
WHERE 1=1
AND p.ProjectGUID = @ProjectGUID
-- 2. 撈出檢查表
SELECT
'Project' AS TableName
, CASE
WHEN T.ProjectGUID IS NULL THEN N'新增'
ELSE N'修改'
END AS 'Action'
, CASE
WHEN T.ProjectGUID IS NULL THEN ''
ELSE
SUBSTRING(
CASE WHEN ISNULL(CONVERT(VARCHAR(40), T.SystemGUID), '') <> ISNULL(CONVERT(VARCHAR(40), S.SystemGUID), '') THEN ', SystemGUID' ELSE '' END
+ CASE WHEN ISNULL(T.ProjectName, '') <> ISNULL(S.ProjectName, '') THEN ', ProjectName' ELSE '' END
+ CASE WHEN ISNULL(T.ImportID, '') <> ISNULL(S.ImportID, '') THEN ', ImportID' ELSE '' END
+ CASE WHEN ISNULL(T.[Server], '') <> ISNULL(S.[Server], '') THEN ', Server' ELSE '' END
+ CASE WHEN ISNULL(T.DBName, '') <> ISNULL(S.DBName, '') THEN ' DBName' ELSE '' END
+ CASE WHEN ISNULL(T.Creator, '') <> ISNULL(S.Creator, '') THEN ', Creator' ELSE '' END
+ CASE WHEN ISNULL(T.CreateDate, '1990-01-01') <> ISNULL(S.CreateDate, '1990-01-01') THEN ', CreateDate' ELSE '' END
+ CASE WHEN ISNULL(T.Maintainer, '') <> ISNULL(S.Maintainer, '') THEN ', Maintainer' ELSE '' END
+ CASE WHEN ISNULL(T.MaintainDate, '1990-01-01') <> ISNULL(S.MaintainDate, '1990-01-01') THEN ', MaintainDate' ELSE '' END
+ CASE WHEN ISNULL(T.[Status], 0) <> ISNULL(S.[Status], 0) THEN ', Status' ELSE '' END
, 3, 1000)
END AS 'Field'
, CAST(T.ProjectGUID AS VARCHAR(50)) [Guid]
, ISNULL(S.ProjectName, '') [Name]
FROM #tmpProject S(NOLOCK)
LEFT JOIN W08DB001.NLIS.dbo.Project T(NOLOCK) ON T.ProjectGUID = S.ProjectGUID
WHERE 1=1
AND (
T.ProjectGUID IS NULL
OR ISNULL(CONVERT(VARCHAR(40), T.SystemGUID), '') <> ISNULL(CONVERT(VARCHAR(40), S.SystemGUID), '')
OR ISNULL(T.ProjectName, '') <> ISNULL(S.ProjectName, '')
OR ISNULL(T.ImportID, '') <> ISNULL(S.ImportID, '')
OR ISNULL(T.[Server], '') <> ISNULL(S.[Server], '')
OR ISNULL(T.DBName, '') <> ISNULL(S.DBName, '')
OR ISNULL(T.Creator, '') <> ISNULL(S.Creator, '')
OR ISNULL(T.CreateDate, '1990-01-01') <> ISNULL(S.CreateDate, '1990-01-01')
OR ISNULL(T.Maintainer, '') <> ISNULL(S.Maintainer,'')
OR ISNULL(T.MaintainDate, '1990-01-01') <> ISNULL(S.MaintainDate,'1990-01-01')
OR ISNULL(T.[Status], 0) <> ISNULL(S.[Status], 0)
)
```
新舊資料比對(過版)
---
當不同Server/DB,但是有同樣的Schema,需要把資料過版過去時
```sql=
UPDATE op
SET
op.SystemGUID = np.SystemGUID,
op.ProjectName = np.ProjectName,
op.ImportID = np.ImportID,
op.[Server] = np.[Server],
op.DBName = np.DBName,
op.Maintainer = np.Maintainer,
op.MaintainDate = np.MaintainDate,
op.[Status] = np.[Status]
FROM [dbo].[Project] np(NOLOCK)
JOIN [W08NJDBRD001].[NLIS].[dbo].[Project] op (NOLOCK) ON op.ProjectGUID = np.ProjectGUID
WHERE np.ProjectGUID = @ProjectGUID
SET @Count_Update_Project = @@ROWCOUNT
INSERT INTO [W08NJDBRD001].[NLIS].[dbo].[Project]
(
ProjectGUID,
SystemGUID,
ProjectName,
ImportID,
[Server],
DBName,
[Status]
)
SELECT
@ProjectGUID AS ProjectGUID,np.SystemGUID,np.ProjectName,np.ImportID,np.[Server],np.DBName,np.[Status]
FROM [dbo].[Project] np (NOLOCK)
LEFT JOIN [W08NJDBRD001].[NLIS].[dbo].[Project] op (NOLOCK) ON op.ProjectGUID = np.ProjectGUID
WHERE np.ProjectGUID = @ProjectGUID
AND op.ProjectGUID IS null
SET @Count_Insert_Project = @@ROWCOUNT
```
組合字串拆解更新
---
```sql=
DECLARE
@ExcelColumn VARCHAR(MAX)='col1,col2,col3',
@TableColumn VARCHAR(MAX)='col11,col22,col33',
@Sort VARCHAR(MAX) ='1;2;3',
@CategoryGUID UNIQUEIDENTIFIER,
@User VARCHAR(30)
DECLARE @_i int = 1,@_Count int = 0
--分割ExcelColumn存入暫存Table,並給序號
select [No] = identity(int,1,1), *
into #ExcelColumn
from dbo.f_SplitList(';', @ExcelColumn)
--分割TableColumn存入暫存Table,並給序號
select [No] = identity(int,1,1), *
into #TableColumn
from dbo.f_SplitList(';', @TableColumn)
--分割Sort存入暫存Table,並給序號
select [No] = identity(int,1,1), *
into #Sort
from dbo.f_SplitList(';', @Sort)
--取得要修改的資料數量
set @_Count = (select COUNT(*) from #ExcelColumn)
--用迴圈逐筆修改
while(@_i <= @_Count)
begin
declare @UpdateExcel varchar(100)
,@UpdateTable varchar(100)
,@UpdateSort varchar(100)
--篩選出要更新的Excelcol
set @UpdateExcel = (select ListItem from #ExcelColumn where [No] = @_i)
--篩選出要更新的Tablecol
set @UpdateTable = (select ListItem from #TableColumn where [No] = @_i)
--篩選出要更新的Sort
set @UpdateSort = (select ListItem from #Sort where [No] = @_i)
--新增資料
INSERT INTO ExcelColumnMapping
(
CategoryGUID,
ExcelColumn,
TableColumn,
Sort,
Creator,
CreateDate,
[Status]
)
VALUES
(
@CategoryGUID,
@UpdateExcel,
@UpdateTable,
@UpdateSort,
@User,
GETDATE(),
1
)
set @_i = @_i + 1
end
DROP TABLE #ExcelColumn
DROP TABLE #TableColumn
DROP TABLE #Sort
```
組合字串Self Join更新
---
```sql=
DECLARE @param VARCHAR(MAX) = N'T-XHJ-004-19A,T-ST-007-19JS,T-XHJ-004-19A'
UPDATE tb1
SET tb1.SIZE_ = 'WTF'
FROM [Test].[dbo].[Shipping] tb1
LEFT JOIN [Test].[dbo].[Shipping] tb2 ON (tb1.MPO_DETAIL_RECORD = tb2.MPO_DETAIL_RECORD)
WHERE tb1.SHIP_NO IN (SELECT [Name] FROM dbo.splitstring(@param))
select * from [Test].[dbo].[Shipping](NOLOCK)
```
字串拆解函式
---
```sql=
CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
@returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN
DECLARE @name NVARCHAR(255)
DECLARE @pos INT
WHILE CHARINDEX(',', @stringToSplit) > 0
BEGIN
SELECT @pos = CHARINDEX(',', @stringToSplit)
SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)
INSERT INTO @returnList
SELECT @name
SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
END
INSERT INTO @returnList
SELECT @stringToSplit
RETURN
END
```
MERGE
---
```sql=
```
防禦式 SQL 更新
---
```sql=
SET XACT_ABORT ON
BEGIN TRAN
--實驗用,插入一筆判別 Commit 或 Rollback
INSERT INTO Product VALUES (255,'Committed', -1);
SELECT * FROM Product WHERE Id = 1;
IF @@ROWCOUNT <> 1 THROW 51000, N'Id=1 not found', 1;
UPDATE Product SET Price = 990 WHERE Id = 1 AND Price = 980;
IF @@ROWCOUNT <> 1 THROW 51000, N'Id=1, Price=980 not matched', 1;
SELECT * FROM Product WHERE Id = 1;
COMMIT TRAN
```
交易
---
```sql=
```
Remove Duplicate
---
```sql=
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY ConnectionID ORDER BY ConnectionID)
FROM [Billing].[dbo].[SIP_PBXAmount] (NOLOCK)
WHERE ServerType = 5 AND Type1Connectime BETWEEN '2020/8/1' AND '2020/9/1'
)
DELETE FROM CTE
WHERE RN > 1
```
Add LinkServer
---
```sql=
EXEC master.dbo.sp_addlinkedserver
@server = N'uranium',
@srvproduct=N'SQL Server'
```
```
{"metaMigratedAt":"2023-06-15T11:30:26.124Z","metaMigratedFrom":"YAML","title":"SQL 筆記本","breaks":true,"disqus":"hackmd","contributors":"[{\"id\":\"bf4be45f-3f16-466f-ba9b-911071c79118\",\"add\":8939,\"del\":88}]","description":"當資料是需要彈性Server時"}