Розкажу про 1 трюк для MSSQL який здорово полегшує життя при написанні скриптів. Проблема в тому, що при написанні запитів (зокрема insert`a) часто потрібно вказати таблицю із списком всіх її полів. Якщо полей 5-10, то їх імена можна виписати вручну, але якщо таблички більші, то робити це вручну це вже збочення.


Проблема

Наприклад, є така табличка:

і нам потрібно вставити туди якісь дані за допомогою SQL. Це можна зробити так:

insert into tblGuestBookEntries (gbeDate, gbeName, gbeText, gbeEmail, gbeIcq, gbeIP, gbeBrowser, gbeCommentsCount) values (getdate(), 'test', 'test', null, null, '127.0.0.1', 'test', 0)

або так:

insert into tblGuestBookEntries (gbeDate, gbeName, gbeText, gbeEmail, gbeIcq, gbeIP, gbeBrowser, gbeCommentsCount) select getdate(), 'test', 'test', null, null, '127.0.0.1', 'test', 0 union select getdate(), 'test', 'test', null, null, '127.0.0.1', 'test', 0

Другий варіант трохи зручніший, оскільки можна вставити зразу декілька рядків. Але не про то мова. Як бачимо в обидвох випадках доводиться перелічувати всі поля таблиці. Це доводиться робити, оскільки поле gbeID є автоінкрементним (тобто має identity), і ми не можемо явно вставити туди якесь значення. Зразу спадає на думку вставити туди значення default ось так:

insert into tblGuestBookEntries values (default, getdate(), 'test', 'test', null, null, '127.0.0.1', 'test', 0)

на що SQL Server матюкається так:

Msg 8101, Level 16, State 1, Line 1
An explicit value for the identity column in table 'tblGuestBookEntries' can only be specified when a column list is used and IDENTITY_INSERT is ON.

Я спочатку дуже нашвидкуруч прочитав цей меседж і подумав, що виставлення IDENTITY_INSERT в ON вирішить дану проблему, внаслідок чого сотворився наступний код:

set identity_insert tblGuestBookEntries on insert into tblGuestBookEntries values (isnull(ident_current('tblGuestBookEntries') + 1, 1), getdate(), 'test', 'test', null, null, '127.0.0.1', 'test', 0) set identity_insert dbo.tblGuestBookEntries off

Але запустивши його я отримав цю ж помилку, після чого таки повністю прочитав фразу ... can only be specified when a column list is used ...

Отже без перерахування полей не обійтись.

Вирішення

Перерахувати поля таблиці можна за допомогою спеціальної інформаційної таблиці:

select column_name + ', ' from information_schema.columns where table_name = 'tblGuestBookEntries'

або за допомогою сторед процедури:

sp_columns 'tblGuestBookEntries'

Перший варіант зручніший, бо видає тільки назви полей. Я ще для зручності доставляю кому в кінці. Після видачі всіх полей можна їх копіювати в SQL-код, але оскільки кожне наступне поле в новому рядку, то якщо полей штук так з 20, то виходять макарони, тобто дуже довгий код, який важко переглядати. Тому приходиться ще забрати ентери, для цього я закопійовую все в текстовий редактор і замінюю «\\n» на «». Щоб цього постійно не робити було б добре якби була якась агрегатна функція concat, яка б зліплювала усі записи в один рядок. Нажаль такої функції в MSSQL поки немає, тому доводиться збочуватись. Трохи побавившись з курсорами я вродив таку процедуру:

create proc sprColumnsList ( @tableName varchar(max), @delimiter varchar(max) = ', ' ) as begin declare mycursor cursor for select column_name from information_schema.columns where table_name = @tableName declare @allColumns varchar(max) declare @curColumn varchar(max) open mycursor fetch next from mycursor into @allColumns while 1=1 begin fetch next from mycursor into @curColumn if (@@fetch_status <> 0) break; set @allColumns = @allColumns + @delimiter + @curColumn end close mycursor deallocate mycursor select @allColumns as ColumnsList end

Тут створюється курсор, який пробігається по всіх ряках з назвами полей таблиці, запихає їх у змінну і виводить її.

Тепер можна отримати список полей таблиці просто виконавши

sprColumnsList 'tblGuestBookEntries'

Приклад 2:

declare @x varchar(max) set @x = ',' + char(13) + char(9) exec sprColumnsList 'tblUsers', @x

Тут отримуємо список із комою, переносом рядка і одним табом зліва. (Щоб показувались переноси рядків у MSSQL Management Studio, треба включити текстовий вивід: у Tools > Options > Query Results виставити Results to text)

До речі, з появою MSSQL 2005 появився ще 1 спосіб. Тепер можна писати сторед процедури на .NET мовах (C#, VB.NET, ...). Цього способу я ще не досліджував, але він дуже підходить для цієї проблемки.