Ms Sql |
Разработка расширенных хранимых процедур |
SQL Server™ 2000 Reporting |
Хранение и поиск текстов |
Основы I/O в SQL Server 2000 |
Восстановление удалённой таблицы или отдельных её строк |
Восстановление backup в базу с другим именем |
RESTORE FILELISTONLY FROM DISK = 'c:\mssql\t2_20051222_1327.bak' GO -- Restore the files for KK. RESTORE DATABASE KK FROM DISK = 'c:\mssql\t2_20051222_1327.bak' WITH REPLACE, MOVE 'T2SQL' TO 'C:\MsSql\Data\KK_Data.MDF', MOVE 'T2SQL_log' TO 'C:\MsSql\Data\KK_Log.LDF' GO |
Страничная навигация с ROWCOUNT и ROW_NUMBER() |
declare @Page int declare @PageSize int set @Page = 500 set @PageSize = 10 begin declare @RowsCount int declare @FirstSelectingRowNumber int declare @FirstSelectingRowId int select @RowsCount = count(Id) from table1 set @FirstSelectingRowNumber = (@Page - 1) * @PageSize + 1 if (@FirstSelectingRowNumber <= @RowsCount) begin SET ROWCOUNT @FirstSelectingRowNumber SELECT @FirstSelectingRowId = id FROM table1 ORDER BY 1 SET ROWCOUNT @PageSize SELECT * FROM table1 WHERE id >= @FirstSelectingRowId ORDER BY 1 end end |
SELECT Description, Date FROM (SELECT ROW_NUMBER() OVER (ORDER BY Date DESC) AS Row, Description, Date FROM LOG) AS LogWithRowNumbers WHERE Row >= 1 AND Row <= 10 |
Пример использования курсора |
DECLARE CURSOR1 CURSOR LOCAL FORWARD_ONLY FOR SELECT id, code, chcode from t_dealers WHERE filial_id=@filial_source_id FOR UPDATE OF code, chcode SET @Cursor=1 OPEN CURSOR1 SET @Cursor=2 WHILE( @Cursor=2 ) BEGIN FETCH NEXT FROM CURSOR1 INTO @id, @intcode, @strcode IF @@fetch_status=-1 BREAK IF @@fetch_status=-2 CONTINUE ... SET @strcode = RIGHT('000' + RTRIM(STR(@intcode)),4) UPDATE t_dealers SET code=@intcode, chcode=@strcode WHERE CURRENT OF CURSOR1 END CLOSE CURSOR1 DEALLOCATE CURSOR1 SET @Cursor=0 |
Как искать строки, в которых присутствуют спецсимволы %_? |
Такие символы нужно заключать в квадратные скобки:
|
Рекурсивный вызов триггеров |
Прямой рекурсии триггера на одно и то же событие не происходит. Косвенная рекурсия возможна. Т.е. - если в триггере на update сделать update этой же таблицы, то триггер второй раз не вызовется, но если update будет сделан в ХП, которая вызвана в триггере, то вызовется уже другой экземпляр триггера на update. Также триггеры на разные события вызываются друг из друга. Только для всего этого необходимо, чтобы параметр сервера 'nested triggers' имел значение 1. Проверить это можно, вызвав команду "sp_configure 'nested triggers'" и проверив колонку "run_value". |
Игра с триггером |
DECLARE @history_id AS INT BEGIN TRAN DELETE FROM tblMember WHERE intMemberId=@id SET @history_id = @@IDENTITY UPDATE tblmember_history SET vchUpdatedByWho = @user WHERE id = @history_id COMMIT TRAN |
Сжатие базы |
BACKUP LOG BaseName WITH TRUNCATE_ONLY GO DBCC SHRINKDATABASE( 'BaseName') GO |
Передача массива процедуре |
CREATE FUNCTION dbo.GetTableVarchar(@Data image) RETURNS @DataTable TABLE (RowID int primary key IDENTITY , Value Varchar(8000)) AS BEGIN --First Test the data is of type Varchar. IF(dbo.ValidateExpectedType(103, @Data) != 1) RETURN --Loop thru the list inserting each -- item into the variable table. DECLARE @Ptr int, @Length int, @VarcharLength smallint, @Value Varchar(8000) SELECT @Length = DataLength(@Data), @Ptr = 2 WHILE(@Ptr < @Length) BEGIN --The first 2 bytes of each item is the length of the --varchar, a negative number designates a null value. SET @VarcharLength = SUBSTRING(@Data, @ptr, 2) SET @Ptr = @Ptr + 2 IF(@VarcharLength < 0) SET @Value = NULL ELSE BEGIN SET @Value = SUBSTRING(@Data, @ptr, @VarcharLength) SET @Ptr = @Ptr + @VarcharLength END INSERT INTO @DataTable (Value) VALUES(@Value) END RETURN END CREATE PROCEDURE GetSnailDetails @SnailIDs image AS SELECT Snail.* FROM dbo.GetTableInt(@SnailIDs) SIDs INNER JOIN Snails ON SIDs.Value = Snails.SnailID GO |
CREATE FUNCTION dbo.CharToInt ( @data varchar(8000) ) RETURNS @Table TABLE (ind int primary key IDENTITY, value int) AS BEGIN DECLARE @Value int DECLARE @I int DECLARE @J int DECLARE @L int DECLARE @ch char(1) SET @I=1 SET @L=LEN(@data) WHILE( @I <= @L ) BEGIN SET @J=@I WHILE( @I-@J < 16 ) BEGIN SET @ch = SUBSTRING(@data,@I,1) IF @ch<'0'OR @ch>'9' BREAK SET @I= @I+1 IF @I > @L BREAK END SET @value= CONVERT(int,SUBSTRING(@data,@J,@I-@J)) INSERT INTO @Table (Value) VALUES(@Value) SET @I=@I+1 END RETURN END CREATE PROCEDURE Test @users varchar(8000) AS select * INTO #users from dbo.chartoint(@users) GO |
@@IDENTITY |
|
Модификация текстового поля |
Удаление фрагментаdeclare @id int declare @pos int declare @cnt int declare @rows int declare @PtrVal varbinary(16) DECLARE @Len int DECLARE @Size int CREATE TABLE #Tmp( ind int IDENTITY, m_id uniqueidentifier, msg text ) insert into #Tmp(m_id,msg) select m_id, XM_XH_TEXT from XT where XM_XH_TEXT like '%<cut />%' set @rows = @@rowcount set @id = 1 while( @id <= @rows ) begin set @cnt = 0 while( 1 = 1 ) begin SELECT @Len= DATALENGTH(msg)-1, @PtrVal = TEXTPTR(msg), @Pos = PATINDEX( '%<cut/>%', msg ) FROM #Tmp WHERE ind= @id if @pos < = 0 break set @pos = @pos - 1 UPDATETEXT #Tmp.msg @PtrVal @pos 7 set @cnt = @cnt + 1 end break set @id = @id + 1 end update XT set XT.XM_XH_TEXT = #Tmp.Msg from XT inner join #Tmp on #Tmp.m_id = XT.m_id |
Отображение текстового поля |
CREATE PROCEDURE dbo.read_Flash @Id int AS BEGIN DECLARE @PtrVal varbinary(16) DECLARE @Buf varchar(200) DECLARE @Len int DECLARE @Size int CREATE TABLE #Tmp( ind int IDENTITY, msg text ) CREATE TABLE #Msg( ind int IDENTITY, msg varchar(200) ) INSERT #Tmp(msg) SELECT fl_text FROM ut_flash WHERE fl_id=@Id IF @@rowcount=0 GOTO ERREXIT SELECT @Len=DATALENGTH(msg)-1, @PtrVal=TEXTPTR(msg) FROM #Tmp WHERE ind=1 WHILE(@Len>0 ) BEGIN INSERT #Msg(msg) SELECT SUBSTRING(CONVERT(char(200),msg),1,200) FROM #Tmp WHERE ind=1 SELECT @Size=CASE WHEN @Len-200 < 0 THEN @Len ELSE 200 END UPDATETEXT #Tmp.msg @PtrVal 0 @Size SELECT @Len=@Len-200 END SELECT msg FROM #Msg RETURN 0 ERREXIT: SELECT NULL RETURN -1 END |
Удаление колонок |
DECLARE @tableId int SET @tableId = (SELECT id FROM sysobjects WHERE name = 'tblSystem' and type= 'U') IF @tableId > 0 BEGIN IF EXISTS( SELECT id FROM syscolumns WHERE name = 'intRegionCityId' AND id=@tableId ) BEGIN ALTER TABLE tblSystem DROP COLUMN intRegionCityId ALTER TABLE tblSystem_History DROP COLUMN intRegionCityId ALTER TABLE tblSystem_Archive DROP COLUMN intRegionCityId END END ELSE BEGIN PRINT 'Не найдены колонки' END |
Генерация таблицы на основе запроса |
SELECT xm_client_id, CONVERT(bit, 0) AS IsOK INTO #client FROM xt_finaccount |
sql_variant |
SELECT DATALENGTH(xm_data), SQL_VARIANT_PROPERTY(xm_data,'BaseType'), SQL_VARIANT_PROPERTY(xm_data,'TotalBytes'), xm_data FROM dbo.XT_DC_DATA |
Копирование таблицы |
INSERT pt_page SELECT * FROM ut_page |
Построение деревьев |
Получение массива подчиненных узлов дерева |
DECLARE @Lvl int CREATE TABLE #Nodes ( ind int IDENTITY(1,1), lvl int default(0), node_id int, parent_id int ) SET @Lvl =0 INSERT INTO #Nodes(lvl,node_id,parent_id) SELECT @Lvl, id, parent_id FROM ut_sort WHERE id = @Id WHILE( @Lvl > = 0 ) BEGIN INSERT INTO #Nodes(lvl,node_id,parent_id) SELECT @Lvl+1, id, parent_id FROM ut_sort WHERE parent_id IN (SELECT node_id FROM #Nodes WHERE Lvl=@Lvl) IF @@rowcount=0 BREAK SET @Lvl=@Lvl+1 END SELECT * FROM #Nodes |
Определение прав для узлов деревьев |
-- Список ролей insert into #r(role_id) select role_id from uf_roles(@roles) -- Права на сущность set @rt = (select CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x01 = 0x01 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x01 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x02 = 0x02 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x02 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x04 = 0x04 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x04 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x08 = 0x08 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x08 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x10 = 0x10 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x10 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x20 = 0x20 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x20 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x40 = 0x40 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x40 END + CASE WHEN SUM(CASE WHEN ut_table_role.tb_right & 0x80 = 0x80 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x80 END as tb_right from ut_table_role inner join ut_table on ut_table.id = ut_table_role.table_id where ut_table.tb_name = 'ut_folder' and ut_table_role.role_id in (select role_id from #r)) -- Права для родительской папки if @parent_id is not null begin set @id = @parent_id while( @id is not null ) begin insert into #p(fd_id,fd_allow,fd_deny) select page_role.folder_id, CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x01 = 0x01 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x01 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x02 = 0x02 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x02 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x04 = 0x04 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x04 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x08 = 0x08 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x08 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x10 = 0x10 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x10 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x20 = 0x20 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x20 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x40 = 0x40 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x40 END + CASE WHEN SUM(CASE WHEN page_role.fd_allow & 0x80 = 0x80 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x80 END as fd_allow, CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x01 = 0x01 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x01 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x02 = 0x02 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x02 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x04 = 0x04 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x04 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x08 = 0x08 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x08 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x10 = 0x10 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x10 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x20 = 0x20 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x20 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x40 = 0x40 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x40 END + CASE WHEN SUM(CASE WHEN page_role.fd_deny & 0x80 = 0x80 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x80 END as fd_deny from ut_folder_role page_role where page_role.folder_id = @id and page_role.role_id in (select role_id from #r) group by page_role.folder_id set @id = (select parent_id from ut_folder where id=@id) end -- Спускаюсь вниз для определения прав set @ind = isnull((select max(ind) from #p),0) while( @ind > 0 ) begin set @rt = (select (@rt | fd_allow) & ~(fd_deny) from #p where ind = @ind) set @ind = @ind - 1 end truncate table #p -- Создаю список страниц insert into #p(fd_id,fd_allow,fd_deny) select page.id, ISNULL(CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x01 = 0x01 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x01 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x02 = 0x02 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x02 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x04 = 0x04 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x04 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x08 = 0x08 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x08 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x10 = 0x10 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x10 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x20 = 0x20 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x20 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x40 = 0x40 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x40 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_allow,0) & 0x80 = 0x80 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x80 END,0) as fd_allow, ISNULL(CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x01 = 0x01 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x01 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x02 = 0x02 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x02 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x04 = 0x04 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x04 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x08 = 0x08 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x08 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x10 = 0x10 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x10 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x20 = 0x20 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x20 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x40 = 0x40 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x40 END + CASE WHEN SUM(CASE WHEN ISNULL(page_role.fd_deny,0) & 0x80 = 0x80 THEN 1 ELSE 0 END) = 0 THEN 0 ELSE 0x80 END,0) as fd_deny from ut_folder page left join ut_folder_role page_role on page_role.folder_id = page.id and page_role.role_id in (select role_id from #r) where page.parent_id = @parent_id group by page.id set nocount off select id, isnull(t0.parent_id,0) as parent_id, t0.fd_name, (select count(*) from ut_folder t1 where t1.parent_id=t0.id) as fd_count, ((@rt | #p.fd_allow) & ~(#p.fd_deny)) as fd_right, t0.fd_isSystem, t0.fd_isVisible from ut_folder t0 inner join #p on #p.fd_id = t0.id where t0.parent_id = @parent_id order by t0.fd_name |
CREATE FUNCTION dbo.uf_roles (@role as varchar(1000)) RETURNS @RoleTable TABLE (ind int primary key IDENTITY, role_id int) AS BEGIN declare @I int declare @J int declare @L int declare @role_id int declare @ch char(1) declare @str varchar(16) SELECT @J=1, @L=DATALENGTH(RTRIM(@role)) WHILE( @J <= @L ) BEGIN SET @I= @J WHILE( @J <= @L ) BEGIN SET @ch=SUBSTRING(@role,@J,1) IF @ch = ',' BREAK SET @J=@J+1 END IF @ch = ',' SET @str=SUBSTRING(@role,@I,@J-@I) ELSE SET @str=SUBSTRING(@role,@I,@J-@I+1) SET @role_id=CONVERT(int,@str) IF @role_id > 0 INSERT INTO @RoleTable (role_id) VALUES(@role_id) SET @J=@J+1 END RETURN END |
Установка лидирующих нулей |
SELECT RIGHT('000' + LTRIM(STR(1)),4) SELECT REPLACE(STR(1,4),' ','0') |
Поиск свободной позиции в цепочке |
SET @intcode = ISNULL(SELECT MIN(code-1) FROM t_dealers t1 WHERE t1.filial_id = @filial_target_id AND not exists(SELECT * FROM t_dealers t2 WHERE t2.code=t1.code-1 AND filial_id=@filial_target_id),1) IF @intcode = 0 BEGIN SET @intcode =ISNULL(SELECT MIN(code+1),1) FROM t_dealers t1 WHERE t1.filial_id = @filial_target_id AND not exists(SELECT * FROM t_dealers t2 WHERE t2.code=t1.code+1 AND filial_id=@filial_target_id),1) END |
Вложенные процедуры |
Create Procedure dbo.xxsp_currate_add @xm_currency_id uniqueidentifier, @xm_publication_id uniqueidentifier = NULL, @xm_datefrom datetime, @xm_ratio float = 1, @xm_basecurrencyvalue float, @xm_currencyvalue float, @recid uniqueidentifier = null output As begin DECLARE @tran int DECLARE @err int SET @err = -1 IF @@NESTLEVEL = 1 SET NOCOUNT ON SET @tran = @@TRANCOUNT IF @tran =0 BEGIN TRAN currate_add ELSE SAVE TRAN currate_add ... INSERT ... IF @@rowcount=0 GOTO ERR_RETURN ... OK_RETURN: IF @tran = 0 COMMIT TRAN currate_add IF @@NESTLEVEL = 1 SELECT 0 AS Error RETURN 0 ERR_RETURN: ROLLBACK TRAN currate_add IF @@NESTLEVEL = 1 SELECT @err AS Error RETURN @err end |
Чтение dbf из MS SQL |
exec sp_addlinkedserver 'DBF_PGB', 'Jet 4.0', 'Microsoft.Jet.OLEDB.4.0', 'c:\work\pgb', NULL, 'dBase IV' go exec sp_addlinkedsrvlogin @rmtsrvname = 'DBF_PGB', @useself = false, @locallogin = NULL, @rmtuser = NULL, @rmtpassword = NULL go exec sp_tables_ex N'DBF_PGB' SELECT * FROM DBF_PGB...BNKSEEK go exec sp_droplinkedsrvlogin @rmtsrvname = 'DBF_PGB', @locallogin = NULL go exec sp_dropserver @server = 'DBF_PGB' go |
OPENROWSET |
SELECT * FROM OPENROWSET( 'MSDASQL', 'Driver= {MicrosoftVisualFoxProDriver};SourceType=DBF;SourceDb=c:\work\pgb\BNKSEEK.DBF;', 'select * from c:\work\pgb\BNKSEEK.DBF' ) as dbf SELECT * FROM OPENROWSET( 'MSDASQL', 'Driver=Microsoft Excel Driver (*.xls);DBQ=c:\ramsql7', 'SELECT * FROM [sheet1$]' ) as xls |
Скрипт перемещения логинов с паролями и оригинальными SID между SQL серверами |
1. Выполните представленный ниже скрипт на SQL сервере с которого необходимо перенести логины. Этот скрипт создаёт два хранимых процедуры с именами sp_hexadecimal и sp_help_revlogin в системной базе данных master. После успешного исполнения скрипта, выполните операции из пункта 2. ОБРАТИТЕ ВНИМАНИЕ: Создаваемые в процессе исполнения скрипта процедуры напрямую оперируют с системными таблицами SQL Server. Структура этих таблиц может изменяться от версии к версии SQL Server, что может повлиять на работоспособность этого скрипта. ----- Begin Script, Create sp_help_revlogin procedure ----- USE master GO IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL DROP PROCEDURE sp_hexadecimal GO CREATE PROCEDURE sp_hexadecimal @binvalue varbinary(256), @hexvalue varchar(256) OUTPUT AS DECLARE @charvalue varchar(256) DECLARE @i int DECLARE @length int DECLARE @hexstring char(16) SELECT @charvalue = '0x' SELECT @i = 1 SELECT @length = DATALENGTH (@binvalue) SELECT @hexstring = '0123456789ABCDEF' WHILE (@i <= @length) BEGIN DECLARE @tempint int DECLARE @firstint int DECLARE @secondint int SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1)) SELECT @firstint = FLOOR(@tempint/16) SELECT @secondint = @tempint - (@firstint*16) SELECT @charvalue = @charvalue + SUBSTRING(@hexstring, @firstint+1, 1) + SUBSTRING(@hexstring, @secondint+1, 1) SELECT @i = @i + 1 END SELECT @hexvalue = @charvalue GO IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL DROP PROCEDURE sp_help_revlogin GO CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS DECLARE @name sysname DECLARE @xstatus int DECLARE @binpwd varbinary (256) DECLARE @txtpwd sysname DECLARE @tmpstr varchar (256) DECLARE @SID_varbinary varbinary(85) DECLARE @SID_string varchar(256) IF (@login_name IS NULL) DECLARE login_curs CURSOR FOR SELECT sid, name, xstatus, password FROM master..sysxlogins WHERE srvid IS NULL AND name <> 'sa' ELSE DECLARE login_curs CURSOR FOR SELECT sid, name, xstatus, password FROM master..sysxlogins WHERE srvid IS NULL AND name = @login_name OPEN login_curs FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd IF (@@fetch_status = -1) BEGIN PRINT 'No login(s) found.' CLOSE login_curs DEALLOCATE login_curs RETURN -1 END SET @tmpstr = '/* sp_help_revlogin script ' PRINT @tmpstr SET @tmpstr = '** Generated ' + CONVERT (varchar, GETDATE()) + ' on ' + @@ServerNAME + ' */' PRINT @tmpstr PRINT '' PRINT 'DECLARE @pwd sysname' WHILE (@@fetch_status <> -1) BEGIN IF (@@fetch_status <> -2) BEGIN PRINT '' SET @tmpstr = '-- Login: ' + @name PRINT @tmpstr IF (@xstatus & 4) = 4 BEGIN -- NT authenticated account/group IF (@xstatus & 1) = 1 BEGIN -- NT login is denied access SET @tmpstr = 'EXEC master..sp_denylogin ''' + @name + '''' PRINT @tmpstr END ELSE BEGIN -- NT login has access SET @tmpstr = 'EXEC master..sp_grantlogin ''' + @name + '''' PRINT @tmpstr END END ELSE BEGIN -- SQL Server authentication IF (@binpwd IS NOT NULL) BEGIN -- Non-null password EXEC sp_hexadecimal @binpwd, @txtpwd OUT IF (@xstatus & 2048) = 2048 SET @tmpstr = 'SET @pwd = CONVERT (varchar(256), ' + @txtpwd + ')' ELSE SET @tmpstr = 'SET @pwd = CONVERT (varbinary(256), ' + @txtpwd + ')' PRINT @tmpstr EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name + ''', @pwd, @sid = ' + @SID_string + ', @encryptopt = ' END ELSE BEGIN -- Null password EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name + ''', NULL, @sid = ' + @SID_string + ', @encryptopt = ' END IF (@xstatus & 2048) = 2048 -- login upgraded from 6.5 SET @tmpstr = @tmpstr + '''skip_encryption_old''' ELSE SET @tmpstr = @tmpstr + '''skip_encryption''' PRINT @tmpstr END END FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd END CLOSE login_curs DEALLOCATE login_curs RETURN 0 GO ----- End Script ----- 2. После того, как будет создана хранимая процедура sp_help_revlogin, запустите эту процедуру в Query Analyzer на исходном сервере: EXEC master..sp_help_revlogin Хранимая процедура sp_help_revlogin может использоваться и на SQL Server 7.0 и на SQL Server 2000. Результат, выводимый sp_help_revlogin, представляет собой готовый скрипт, который создаёт логины с оригинальными SID и паролям. Сохраните выведенный в окно результатов исполнения скрипта текст, и затем выполните его как скрипт в Query Analyzer на том SQL сервере,куда необходимо перенести логины |
XML в MS SQL |
Работа с IDENTITY |
Удаление С помощью ALTER TABLE в 7.0 действительно нельзя убрать свойство IDENTITY с поля. Enterprise Manager убирает IDENTITY с помощью создания новой временной таблицы, переноса в нее данных, удаления старой таблицы и переименования временной таблицы. Если исходная таблица связана с другими или имеет множество индексов, то эта процедура еще более усложняется : BEGIN TRANSACTION CREATE TABLE dbo.Tmp_ABC ( A1 int NOT NULL, A2 char(2) NULL ) ON [PRIMARY] IF EXISTS(SELECT * FROM dbo.ABC) EXEC('INSERT INTO dbo.Tmp_ABC(A1, A2) SELECT A1, A2 FROM dbo.ABC TABLOCKX') DROP TABLE dbo.ABC EXECUTE sp_rename 'dbo.Tmp_ABC', 'ABC' COMMITВы должны иметь свободный объем БД, приблизительно равный объему исходной таблицы (при больших объемах эта операция к тому же и очень длительная). Есть другие способы ликвидации IDENTITY : - создать новое поле в таблице с такими же характеристиками, что и исходное, но без IDENTITY. С помощью UPDATE перенести информацию, удалить старое поле, новое поле переименовать, создать все необходимые CONSTRAINT - поработать на уровне системных таблиц SYSOBJECTS и SYSCOLUMNS (это хакерский вариант, за последствия которого отвечаете только вы) -- примерный скрипт update sysobjects set status=значение where name='ИмяТаблицы' update syscolumns set autoval=NULL where name='ИмяПоля' and OBJECT_ID('ИмяТаблицы')=idОтключение IF NOT IDENT_SEED('ИмяТаблицы') IS NULL SET IDENTITY_INSERT ИмяТаблицы ONСледует обратить внимание, что одновременно отключать IDENTITY можно только у одной таблицы. Включение IF NOT IDENT_SEED('ИмяТаблицы') IS NULL SET IDENTITY_INSERT ИмяТаблицы OFF |
Регулярные выражения в MS SQL |
CREATE PROCEDURE [dbo].sp_RegExpReplace @strIn1 varchar(8000), @strIn2 varchar(8000), @strPattern varchar(2000), @strOut varchar(8000) OUT AS DECLARE @object int, @hr int DECLARE @src varchar(255), @desc varchar(255) -- создаем объект RegExp для работы с регулярными выражениями EXEC @hr = sp_OACreate 'VBScript.RegExp', @object OUT IF (@hr <> 0) BEGIN EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc RETURN END EXEC @hr = sp_OASetProperty @object, 'Pattern', @strPattern IF (@hr <> 0) BEGIN EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc RETURN @hr END -- будет глобальная замена EXEC @hr = sp_OASetProperty @object, 'Global', 1 IF (@hr <> 0) BEGIN EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc RETURN @hr END -- вызов метода Replace EXEC @hr = sp_OAMethod @object, 'Replace', @strOut OUT, @strIn1, @strIn2 IF (@hr <> 0) BEGIN EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc RETURN @hr END -- удаляем объект EXEC @hr = sp_OADestroy @object IF (@hr <> 0) BEGIN EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc RETURN @hr END RETURN 0 |
Рекурсивный запрос |
Рекурсивные запросы используют довольно редко, прежде всего, из-за их сложного и
непонятного синтаксиса:with [recursive] <имя_алиаса_запроса> [ (<список столбцов>) ]
create table tree_sample (
with recursive tree (nm, id, level, pathstr)
|
Cannot resolve the collation conflict |
Принудительное указание COLLATE при создании таблицы
CREATE TABLE #Tabl ( CntrId int, data datetime, nomer char(10), type char(1) COLLATE SQL_Latin1_General_CP1251_CI_AS , doc char(1) COLLATE SQL_Latin1_General_CP1251_CI_AS, ) |
Привидение к одинаковому COLLATE при операции сравнения
INNER JOIN DOC d ON d.subcod COLLATE Cyrillic_General_CI_AS =#Tabl.type AND d.cod COLLATE Cyrillic_General_CI_AS =#Tabl.doc |
Приведение к одинаковому COLLATE при операции UNION
SELECT CntrId, c.NAME COLLATE Cyrillic_General_CI_AS |
Таблица из строки |
declare @inp varchar(1000) SET @inp = 'Иванов, Петров, Сидоров, Дудкин, Пупкин, Билли, Боря' declare @s varchar(1000) set @s='select ltrim('''+ replace(@inp, ',', ''') name union all select ltrim(''')+''')' print(@s) exec (@s) |
Строки из таблицы |
select (select ', ' + name from dbo.T_User_City where dbo.T_User_City.CountryId = dbo.T_User_Country.Id for xml path('') ) as city, name from dbo.T_User_Country |