Insert ms sql: INSERT (Transact-SQL) — SQL Server
Содержание
Оптимизация INSERT (Часть 1)
Введение
Недавно, мы проводили лабораторные испытания в Microsoft Enterprise Engineering Center, при которых использовалась большая рабочая нагрузка, характерная для OLTP систем. Целью этой лабораторной работы было определить, что случится при увеличении числа процессоров с 64 до 128, при обслуживании Microsoft SQL Server интенсивной рабочей нагрузки (примечание: эта конфигурация была ориентирована на релиз Microsoft SQL Server 2008 R2). Рабочая нагрузка представляла собой хорошо распараллеленные операции вставки, направляемые в несколько больших таблиц.
Рабочая нагрузка масштабировалась до 128 процессорных ядер, но в статистике ожиданий было очень много кратких блокировок PAGELATCH_UP и PAGELATCH_EX. Средняя продолжительность ожидания была десятки миллисекунд, и таких ожиданий было очень много. Такое их количество оказалось для нас неожиданностью, ожидалось, что продолжительность не будет превышать несколько миллисекунд.
В этой технической заметке вначале будет описано, как диагностировать подобную проблему и как для разрешения подобной проблемы использовать секционирование таблиц.
Диагностика проблемы
Когда в sys.dm_os_wait_stats наблюдается большое число PAGELATCH, с помощью sys.dm_os_waiting_tasks можно определить сессию и ресурс, который задача ожидает, например, с помощью этого сценария:
SELECT session_id, wait_type, resource_description
FROM sys.dm_os_waiting_tasks
WHERE wait_type LIKE ‘PAGELATCH%’
Пример результата:
В столбце resource_description указаны местоположения страниц, к которым ожидают доступ сессии, местоположение представлено в таком формате:
<database_id>:<file_id>:<page_id>
Опираясь на значения в столбце resource_description, можно составить довольно сложный сценарий, который предоставит выборку всех попавших в список ожидания страниц:
SELECT wt.session_id, wt.wait_type, wt.wait_duration_ms
, s.name AS schema_name
, o.name AS object_name
, i.name AS index_name
FROM sys.dm_os_buffer_descriptors bd
JOIN (
SELECT *
, CHARINDEX(‘:’, resource_description) AS file_index
, CHARINDEX(‘:’, resource_description
, CHARINDEX(‘:’, resource_description)) AS page_index
, resource_description AS rd
FROM sys.dm_os_waiting_tasks wt
WHERE wait_type LIKE ‘PAGELATCH%’
) AS wt
ON bd.database_id = SUBSTRING(wt.rd, 0, wt.file_index)
AND bd.file_id = SUBSTRING(wt.rd, wt.file_index, wt.page_index)
AND bd.page_id = SUBSTRING(wt.rd, wt.page_index, LEN(wt.rd))
JOIN sys.allocation_units au ON bd.allocation_unit_id = au.allocation_unit_id
JOIN sys.partitions p ON au.container_id = p.partition_id
JOIN sys.indexes i ON p.index_id = i.index_id AND p.object_id = i.object_id
JOIN sys.objects o ON i.object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| SELECT wt.session_id, wt.wait_type, wt.wait_duration_ms , s.name AS schema_name , o.name AS object_name , i.name AS index_name FROM sys.dm_os_buffer_descriptors bd JOIN ( SELECT * , CHARINDEX(‘:’, resource_description) AS file_index , CHARINDEX(‘:’, resource_description , CHARINDEX(‘:’, resource_description)) AS page_index , resource_description AS rd FROM sys.dm_os_waiting_tasks wt WHERE wait_type LIKE ‘PAGELATCH%’ ) AS wt ON bd.database_id = SUBSTRING(wt.rd, 0, wt.file_index) AND bd.file_id = SUBSTRING(wt.rd, wt.file_index, wt.page_index) AND bd.page_id = SUBSTRING(wt.rd, wt.page_index, LEN(wt.rd)) JOIN sys.allocation_units au ON bd.allocation_unit_id = au.allocation_unit_id JOIN sys.partitions p ON au.container_id = p.partition_id JOIN sys.indexes i ON p.index_id = i.index_id AND p.object_id = i.object_id JOIN sys.objects o ON i.object_id = o.object_id JOIN sys.schemas s ON o.schema_id = s.schema_id |
Сценарий показал, что ожидаемые страницы относятся к кластеризованному индексу, определённому первичным ключом таблицы с представленной ниже структурой:
CREATE TABLE HeavyInsert (
ID INT PRIMARY KEY CLUSTERED
, col1 VARCHAR(50)
) ON [PRIMARY]
| CREATE TABLE HeavyInsert ( ID INT PRIMARY KEY CLUSTERED , col1 VARCHAR(50) ) ON [PRIMARY] |
Что происходит, почему возникает очередь ожиданий к страницам данных индекса — всё это будет рассмотрено в этой технической заметке.
Основная информация
Чтобы определить, что происходит с нашей большой OLTP-нагрузкой, важно понимать, как SQL Server выполняет вставку в индекс новой строки. При необходимости вставки в индекс новой строки, SQL Server будет следовать следующему алгоритму внесения изменений:
- В журнале транзакций создаётся запись о том, что строка изменилась.
- Осуществляется поиск в В-дереве местонахождения той страницы, куда должна будет попасть новая запись.
- Осуществляется наложение на эту страницу краткой блокировки PAGELATCH_EX, которая призвана воспрепятствовать изменениям из других потоков.
- Осуществляется добавление строки на страницу и, если это необходимо, осуществляется пометка этой страницы как «грязной».
- Осуществляется снятие краткой блокировки со страницы.
В итоге, страница должна будет быть сброшена на диск процессом контрольной точкой или отложенной записи.
Если же все вставки строк направлены на ту же самую страницу, можно наблюдать рост очереди к этой странице. Даже притом, что краткая блокировка весьма непродолжительна, она может стать причиной конкуренции при высоком параллелизме рабочей нагрузки. У нашего клиента, первый и единственный столбец в индексе являлся монотонно возрастающим ключом. Из-за этого, каждая новая вставка шла на ту же самую страницу в конце В-дерева, пока эта страница не была заполнена. Рабочие нагрузки, которые используют в качестве первичного ключа IDENTITY или другие столбцы с последовательно увеличивающимися значениями, также могут столкнуться с подобной проблемой, если распараллеливание достаточно высоко.
Решение
Всегда, когда несколько потоков получают синхронный доступ к одному и тому же ресурсу, может проявиться описанная выше проблема. Стандартное решение состоит в том, чтобы создать больше ресурсов конкурентного доступа. В нашем случае, таким конкурентным ресурсом является последняя страница В-дерева.
Одним из способов снизить конкуренцию за одну страницу состоит в том, чтобы выбрать в качестве первого столбца индекса другой, не увеличивающийся монотонно столбец. Однако, для нашего клиента это потребовало бы внесения изменений на прикладном уровне в клиентских системах. Мы должны были найти другое решение, которое могло бы ограничиться только изменениями в базе данных.
Помните, что местом конкуренции является одна страница в В-дерева, и конкуренция была бы меньше, если бы было возможно использовать для этого несколько В-деревьев, и в то же время работать только с одной таблицей. К счастью, такая возможность есть, это: Секционированные таблицы и индексы. Таблица может быть секционирована таким способом, чтобы новые строки размещались в нескольких секциях.
Сначала нужно создать функцию и схему секционирования:
CREATE PARTITION FUNCTION pf_hash (INT) AS RANGE LEFT FOR VALUES (0,1,2)
CREATE PARTITION SCHEME ps_hash AS PARTITION pf_hash ALL TO ([PRIMARY])
| CREATE PARTITION FUNCTION pf_hash (INT) AS RANGE LEFT FOR VALUES (0,1,2) CREATE PARTITION SCHEME ps_hash AS PARTITION pf_hash ALL TO ([PRIMARY]) |
Представленный выше пример использует четыре секции. Число необходимых секций зависит от числа активных процессов, выполняющих операции INSERT в описанную выше таблицу. Есть некоторая сложность в секционировании таблицы с помощью хэш-столбца, например, в том что всякий раз, когда происходит выборка строк из таблицы, будут затронуты все секции. Это означает, что придётся обращаться более чем к одному В-дереву, т.е. не будет отброшенных оптимизатором за ненадобностью ненужных секций. Будет дополнительная нагрузка на процессоры и некоторое увеличение времени ожиданий процессоров, что побуждает минимизировать число планируемых секций (их должно быть минимальное количество, при котором не наблюдается PAGELATCH). В рассматриваемом нами случае, в системе нашего клиента имелось достаточно много резерва в утилизации процессоров, так что было вполне возможно допустить небольшую потерю времени для инструкций SELECT, и при этом увеличить до необходимых объёмов норму инструкций INSERT.
Ещё одной сложностью является то, что нужен дополнительный столбец, по которому будет выполняться секционирование, т.е. на основании значения которого будут распределяться вставки по четырем секциям. Такого столбца изначально в сценарии Microsoft Enterprise Engineering Center не было. Однако, его достаточно просто было создать. Для этого использовался тот факта, что столбец ID монотонно увеличивается с приращением равным единице, и здесь легко применима довольно простая хеш-функция:
CREATE TABLE HeavyInsert_Hash(
ID INT NOT NULL
, col1 VARCHAR(50)
, HashID AS CAST(ABS(ID % 4) AS TINYINT) PERSISTED NOT NULL)
| CREATE TABLE HeavyInsert_Hash( ID INT NOT NULL , col1 VARCHAR(50) , HashID AS CAST(ABS(ID % 4) AS TINYINT) PERSISTED NOT NULL) |
С помощью столбца HashID, вставки в четыре секции будут выполняться циклически.
Создаём кластеризованный индекс следующим образом:
CREATE UNIQUE CLUSTERED INDEX CIX_Hash
ON HeavyInsert_Hash (ID, HashID) ON ps_hash(HashID)
| CREATE UNIQUE CLUSTERED INDEX CIX_Hash ON HeavyInsert_Hash (ID, HashID) ON ps_hash(HashID) |
Используя новую схему таблицы с секционированием вместо первоначального варианта таблицы, мы сумели избавиться от очередей PAGELATCH и повысить скорость вставки. Этого удалось достичь за счёт балансировки вставки между несколькими секциями и высокого параллелизма. Вставка происходит в несколько страниц, и каждая страница размещается в своей собственной структуре В-дерева. Для нашего клиента удалось повысить производительность вставки на 15 процентов, и справится с большой очередью PAGELATCH к горячей странице индекса одной таблицы. Но при этом удалось также оставить достаточно большой резерв циклов процессоров, что оставило возможность сделать аналогичную оптимизацию для другой таблицы, тоже с высокой нормой вставки.
Строго говоря, суть этой уловки в оптимизации логической схемы первичного ключа таблицы. Однако, потому что ключ просто стал длиннее на величину хеш-функции относительно изначального ключа, дубликатов для столбца ID удалось избежать. Уникальные индексы по единственному столбцу таблицы зачастую становятся причиной проблем с очередями PAGELATCH. Но даже если эту проблему удастся устранить, у таблицы может оказаться другой, некластеризованный индекс, который будет подвержен той же самой проблеме. Как правило, проблема наблюдается для уникальных ключей на единственном столбце, где каждая вставка попадает на одну и ту же страницу. Если и у других таблиц индексы подвержены проблеме с PAGELATCH, можно применить эту же уловку с секционированием к индексам таких таблиц, используя такой же ключ с хэшем в качестве первичного ключа.
Не всегда возможно внести изменения в приложение, особенно, если оно является плодом усилий третьих фирм. Но если изменение запросов возможно, становится доступной их оптимизация за счёт добавления к ним условий фильтрации по предикатам первичного ключа.
Пример: Чтобы отбросить ненужные секции, можно внести следующие изменения в сценарий:
SELECT * FROM HeavyInsert_Hash
WHERE ID = 42
| SELECT * FROM HeavyInsert_Hash WHERE ID = 42 |
Который после изменений будет выглядеть так:
SELECT * FROM HeavyInsert_Hash
WHERE ID = 42 AND HashID = 42 % 4
| SELECT * FROM HeavyInsert_Hash WHERE ID = 42 AND HashID = 42 % 4 |
Исключение оптимизатором ненужных секций по значению хэша не будет вам ничего стоить, если только не считать большой платой за это увеличение на один байт каждой строки кластеризованного индекса.
Вконтакте
Google+
INSERT INTO | Документация ClickHouse
- Справка по SQL
- Выражения
INSERT
Добавление данных.
Базовый формат запроса:
INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ...
Вы можете указать список столбцов для вставки, используя синтаксис (c1, c2, c3)
. Также можно использовать выражение cо звездочкой и/или модификаторами, такими как APPLY, EXCEPT, REPLACE.
В качестве примера рассмотрим таблицу:
SHOW CREATE insert_select_testtable
┌─statement────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CREATE TABLE insert_select_testtable
(
`a` Int8,
`b` String,
`c` Int8
)
ENGINE = MergeTree()
ORDER BY a │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
INSERT INTO insert_select_testtable (*) VALUES (1, 'a', 1)
Если вы хотите вставить данные во все столбцы, кроме ‘b’, вам нужно передать столько значений, сколько столбцов вы указали в скобках:
INSERT INTO insert_select_testtable (* EXCEPT(b)) Values (2, 2)
SELECT * FROM insert_select_testtable
┌─a─┬─b─┬─c─┐
│ 2 │ │ 2 │
└───┴───┴───┘
┌─a─┬─b─┬─c─┐
│ 1 │ a │ 1 │
└───┴───┴───┘
В этом примере мы видим, что вторая строка содержит столбцы a
и c
, заполненные переданными значениями и b
, заполненный значением по умолчанию.
Если список столбцов не включает все существующие столбцы, то все остальные столбцы заполняются следующим образом:
- Значения, вычисляемые из
DEFAULT
выражений, указанных в определении таблицы. - Нули и пустые строки, если
DEFAULT
не определены.
В INSERT можно передавать данные любого формата, который поддерживает ClickHouse. Для этого формат необходимо указать в запросе в явном виде:
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set
Например, следующий формат запроса идентичен базовому варианту INSERT … VALUES:
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ...
ClickHouse отсекает все пробелы и один перенос строки (если он есть) перед данными. Рекомендуем при формировании запроса переносить данные на новую строку после операторов запроса (это важно, если данные начинаются с пробелов).
Пример:
INSERT INTO t FORMAT TabSeparated
11 Hello, world!
22 Qwerty
С помощью консольного клиента или HTTP интерфейса можно вставлять данные отдельно от запроса. Как это сделать, читайте в разделе «Интерфейсы».
Ограничения (constraints)
Если в таблице объявлены ограничения, то их выполнимость будет проверена для каждой вставляемой строки. Если для хотя бы одной строки ограничения не будут выполнены, запрос будет остановлен.
Вставка результатов
SELECT
INSERT INTO [db.]table [(c1, c2, c3)] SELECT ...
Соответствие столбцов определяется их позицией в секции SELECT. При этом, их имена в выражении SELECT и в таблице для INSERT, могут отличаться. При необходимости выполняется приведение типов данных, эквивалентное соответствующему оператору CAST.
Все форматы данных кроме Values не позволяют использовать в качестве значений выражения, такие как now()
, 1 + 2
и подобные. Формат Values позволяет ограниченно использовать выражения, но это не рекомендуется, так как в этом случае для их выполнения используется неэффективный вариант кода.
Не поддерживаются другие запросы на модификацию части данных: UPDATE
, DELETE
, REPLACE
, MERGE
, UPSERT
, INSERT UPDATE
.
Вы можете удалять старые данные с помощью запроса ALTER TABLE ... DROP PARTITION
.
Для табличной функции input() после секции SELECT
должна следовать
секция FORMAT
.
Чтобы вставить значение по умолчанию вместо NULL
в столбец, который не позволяет хранить NULL
, включите настройку insert_null_as_default.
Замечания о производительности
INSERT
сортирует входящие данные по первичному ключу и разбивает их на партиции по ключу партиционирования. Если вы вставляете данные в несколько партиций одновременно, то это может значительно снизить производительность запроса INSERT
. Чтобы избежать этого:
- Добавляйте данные достаточно большими пачками. Например, по 100 000 строк.
- Группируйте данные по ключу партиционирования самостоятельно перед загрузкой в ClickHouse.
Снижения производительности не будет, если:
- Данные поступают в режиме реального времени.
- Вы загружаете данные, которые как правило отсортированы по времени.
Также возможно вставлять данные асинхронно во множественных маленьких вставках. Данные от таких вставок сначала собираются в пачки, а потом вставляются в таблицу. Чтобы включить асинхронный режим, используйте настройку async_insert. Обратите внимание, что асинхронные вставки поддерживаются только через протокол HTTP, а дедупликация при этом не производится.
См. также
SQL.RU | INSERT + ORDER BY
Существует очень раcпространенный миф, что конструкция insert into … select … from … order by … гарантирует последовательность вставки данных в таблицу согласно условию order by. Но это заблуждение, т.к. мы не можем гарантировать последовательность физической вставки данных. Сиквел сам (по своему, неведанному нам сценарию) определяет, как данные попадут в таблицу, последовательно или параллельно и какими кусками определяет оптимизатор. При этом кляуза (clause) просто игнорируется.
Но существует очень интересная особенность, когда в таблице, в которую осуществляется вставка, есть поле IDENTITY
Если перенос данных осуществлять через конструкцию SELECT … INTO:
SELECT Col1, Col2, ID=IDENTITY (int, 1, 1) INTO NewTable FROM OldTable Order By Col1
То данные могут расположиться в новой таблице в совершенно произвольном порядке, например:
Col1 Col2 ID ------- -------- -------- 1 A 4 2 Z 2 7 G 5 11 F 3 17 I 1
Однако, если вставку делать в таблицу, которая создана заранее и содержит поле IDENTITY, то конструкция:
INSERT INTO NewTable (Col1, Col2) SELECT Col1, Col2 FROM OldTable ORDER BY Col1
Гарантирует, что данные в таблице расположатся в нужном порядке:
ID (identity) Col1 Col2 ------------- ------ ------ 1 1 S 2 2 z 3 7 G 4 11 F 5 17 I
При этом мы не повлияли на физический порядок вставки данных, дело в том, что значения для поля IDENTITY были созданы до самой вставки и их порядок соответствует условию ORDER BY.
К сожалению в BOL описано лишь это:
Использование предложения ORDER BY с инструкцией SELECT…INTO для вставки строк из другого источника,
не гарантирует вставку строк в указанном порядке.
В остальном официальный хелп молчит, хотя подобные вопросы очень часто поднимаются, как на наших форумах по MS SQL Server, так и на англоязычных…
Тут же хочу сказать ещё об одной особенности. Если версия вашего SQL Server ниже 10-ой (SQL Server 2008), то подобное поведение отличается от вставки в локальную (на текущем сервере) таблицу и в таблицу расположенную на удаленном сервере (Linked Server). При вставки данных в таблицу (с полем IDENTITY) на удаленном сервере, порядок расположения данных опять не гарантирован.
Эта ситуация признана багом и была «fixed in SQL 2008». Но не отчаивайтесь, если у вас SQL Server 2000 или 2005, т.к. эту особенность можно обойти, если указать в SELECT предложение TOP c числом заведомо больше, чем данных в таблице-источнике.
INSERT INTO RemoteServer.TestDB.SchemaName.NewTable (Col1, Col2) SELECT TOP 1000000000 Col1, Col2 FROM OldTable ORDER BY Col1
Тем самым порядок следования перенесенных данных будет такой же, как при вставке в локальную таблицу.
Ссылки по теме:
http://support.microsoft.com/kb/273586/en-us/
http://blogs.msdn.com/b/sqltips/archive/2005/07/20/441053.aspx
http://sites.google.com/site/venkatrajagopal/sqlblog/msftsupportresponsetoinsertintoselectissue
sql-insert — Русский — it-swarm.com.ru
sql-insert — Русский — it-swarm.com.ru
it-swarm.com.ru
Вставка большого количества записей без блокировки таблицы
Как ВСТАВИТЬ запись или ОБНОВЛЕНИЕ, если это уже существует?
Почему 2 строки затронуты в моем `INSERT … ON DUPLICATE KEY UPDATE`?
LAST_INSERT_ID () MySQL
В SQL всегда ли UPDATE быстрее, чем DELETE + INSERT?
Как вставить значение, содержащее апостроф (одинарную кавычку)?
Каковы различия между INSERT и UPDATE в MySQL?
Избегайте дублирования в запросе INSERT INTO SELECT в SQL Server
SELECT DISTINCT значения и INSERT INTO таблица
Вставьте данные в 3 таблицы одновременно, используя Postgres
Почему массовый импорт быстрее, чем куча вставок?
Решения для INSERT OR ОБНОВЛЕНИЕ на SQL Server
SQL Server: возможно ли вставить в две таблицы одновременно?
Вставить несколько строк в одном запросе SQL?
MSSQL: отключить триггеры для одного INSERT
Добавить строку в результат запроса, используя select
Получение новых идентификаторов после вставки
SQL: INSERT INTO … ЦЕННОСТИ … ВЫБРАТЬ
Экспорт данных в SQL Server как INSERT INTO
Автоматически сопоставлять столбцы в INSERT INTO … SELECT … FROM
Синтаксис для вставки в таблицу без значений?
Как вставить несколько строк БЕЗ повторения части инструкции INSERT INTO dbo.Blah?
SQL Server 2005: вставка нескольких строк одним запросом
Как я могу вставить данные в две таблицы одновременно в SQL Server?
SQL Server, не можете вставить ноль в поле первичного ключа?
Как я могу сделать вставку, где не существует?
Вернуть ID на INSERT?
EntityFramework, вставьте, если не существует, в противном случае обновите
Массовое/пакетное обновление/вставка в PostgreSQL
SQL Server: невозможно вставить явное значение в столбец отметки времени
Как проверить, установлено ли для IDENTITY_INSERT значение ON или OFF в SQL Server?
Как использовать предложение OUTPUT оператора INSERT, чтобы получить значение идентификатора?
Выполнить вставку для каждой строки, взятой из выбора?
Как ускорить производительность вставки в PostgreSQL
Вставьте пустую строку в столбец INT для SQL Server
Пример вставки SQL Server
SQL Вставить в таблицу, только если запись не существует
Вставить в таблицу MySQL PHP
Невозможно вставить явное значение, потому что IDENTITY_INSERT выключено, но не может установить IDENTITY_INSERT в значение ON, потому что оно уже включено
Вставка во временную таблицу из команды Execute
Oracle SQL слияния для вставки и удаления, но не обновления
SQL INSERT INTO с подзапросом и значением
mysql: вставить запись, если не существует, иначе вернуть идентификатор записи
Ошибка SQL: ORA-01861: литерал не соответствует строке формата 01861
Ошибка TSQL при вставке «Строковые или двоичные данные будут обрезаны»
Для каждого дня между двумя датами добавьте строку с одинаковой информацией, но только в этот день в столбцах начала / конца
Как вставить N строк значений по умолчанию в таблицу
В Oracle SQL: как вставить текущую дату + время в таблицу?
Как установить значение по умолчанию при вставке нулевого значения в ненулевой столбец SQL Server?
Ошибка Postgres: нулевое значение в столбце «id» — во время операции вставки
Вставить несколько строк SQL Teradata
Вставьте значение даты в таблицу SQL
Экранирование одинарных кавычек в REDSHIFT SQL
SQL Server INSERT INTO с предложением WHERE
Postgres INSERT ON CONFLICT DO UPDATE против INSERT или UPDATE
SQL Server — Как вставить запись и убедиться, что она уникальна
Можете ли вы получить доступ к значению автоинкремента в MySQL в рамках одного оператора?
Как эффективно вставить тысячи записей в таблицу SQLite с помощью Django?
Как мне обновить, если существует, вставить, если нет (AKA «upsert» или «объединить») в MySQL?
Как вставить значения NULL, используя PDO?
Как получить идентификатор вставки в JDBC?
Как мне несколько раз вставить несколько записей?
Oracle: копировать строку при обновлении одного поля
ВЫБРАТЬ В табличную переменную в T-SQL
Postgres: INSERT, если еще не существует
Вставка SQL с выбранными и жестко запрограммированными значениями
Вставить в таблицу MySQL или обновить, если существует
MySQL и PHP — вставьте NULL вместо пустой строки
MySQL: как вставить запись для каждого результата в запросе SQL?
Вставка SQL Server, если не существует, лучшая практика
PLSQL Вставить в с подзапросом и возвращением предложения (Oracle)
Вставьте и установите значение с max () + 1 задач
Вставить с помощью SELECT
Как сделать пакетную вставку в MySQL
Сохранение метки времени в таблице MySQL с использованием php
postgresql: INSERT INTO … (ВЫБРАТЬ * …)
IDENTITY INSERT и LINQ to SQL
Вставка SqlBulkCopy со столбцом идентификаторов
Вставка нескольких строк в MySQL
PostgreSQL: вставка из другой таблицы
SQL INSERT INTO с SELECT и INNER JOIN
Oracle SQL: использовать последовательность при вставке с оператором выбора
SSIS — удаление строк
Команда вставки C # SQL
SQL — вставка строки и возврат первичного ключа
MySQL: вставить datetime в другое поле datetime
Применение ограничения внешнего ключа для столбцов той же таблицы
Как скопировать строку и вставить в ту же таблицу с автоинкрементным полем в MySQL?
Каковы практические различия между `REPLACE` и` INSERT … ON DUPLICATE KEY UPDATE` в MySQL?
Как я могу вставить значения в таблицу, используя подзапрос с более чем одним результатом?
ExecuteNonQuery: свойство подключения не было инициализировано.
Вставить строки в несколько таблиц в одном запросе, выбирая из вовлеченной таблицы
Вставка данных в таблицу Hive
SQL SELECT INSERT INTO Создать уникальный идентификатор
Как вставить строку в таблицу связанного сервера?
Передача записи в качестве аргумента функции PL / pgSQL
Экспорт определенных строк из таблицы PostgreSQL как SQL-скрипт INSERT
PostgreSQL: дополнительный выбор внутри вставки
Вставка новой строки в таблицу базы данных sql
Как предотвратить повторяющиеся записи из моей таблицы Вставка игнорировать здесь не работает
Content dated before 2011-04-08 (UTC) is licensed under CC BY-SA 2.5. Content dated from 2011-04-08 up to but not including 2018-05-02 (UTC) is licensed under CC BY-SA 3.0. Content dated on or after 2018-05-02 (UTC) is licensed under CC BY-SA 4.0. | Privacy
методов для вставки данных в SQL Server
Сводка
Существует множество способов управления данными для вставки в SQL Server. То, как мы генерируем и вставляем данные в таблицы, может иметь огромное влияние на производительность и удобство обслуживания! Эта тема часто упускается из виду, когда новички думают о ней, но ошибки в том, как мы выращиваем объекты, могут создать огромную головную боль для будущих разработчиков и администраторов.
В этой статье мы рассмотрим различные способы создания и вставки данных как в постоянные, так и во временные объекты.Производительность, синтаксис, документация и ремонтопригодность будут оцениваться для каждого метода. Углубляясь в эту тему, мы можем улучшить дизайн базы данных, качество скриптов и построить объекты, которые легче обслуживать и которые с меньшей вероятностью сломаются из-за обслуживания или выпусков программного обеспечения.
Демо-данные
Во всех демонстрациях в этой статье будут использоваться новые объекты, которые мы здесь создаем. Это позволит нам полностью настраивать, тестировать и ломать его независимо от всего, над чем мы работаем.
Ниже приведен TSQL для создания таблицы с именем dbo.accounts:
СОЗДАТЬ ТАБЛИЦУ dbo.account (account_id INT NOT NULL IDENTITY (1,1) CONSTRAINT PK_account PRIMARY KEY CLUSTERED, account_name VARCHAR (100) NOT NULL, account_start_date DATE NOT NULL, 9000AR account_start_date DATE NOT NULL) NOT NULL, account_type VARCHAR (10) NOT NULL, account_create_timestamp DATETIME NOT NULL, account_notes VARCHAR (500) NULL, is_active BIT NOT NULL); |
Это довольно простая таблица с идентификатором личности и некоторыми столбцами строки / даты для данных учетной записи.По мере работы над этой статьей мы будем добавлять и удалять столбцы, а также настраивать их дальше.
Вставка данных в SQL Server с помощью явного списка столбцов
Давайте начнем с погружения в простейший синтаксис T-SQL: оператор INSERT. Наиболее распространенный способ вставки строк в таблицу — это сделать это с помощью оператора INSERT, в котором мы явно указываем весь список столбцов перед предоставлением значений:
ВСТАВИТЬ В dbo.account (account_name, account_start_date, account_address, account_type, account_create_timestamp, account_notes, is_active) VALUES (‘Ed»s Account’, ‘5/1/2019’, ‘Ed’ Address ‘, ‘ TEST ‘, GETUTCDATE (), ‘ Это тестовая учетная запись для моделирования этих данных. ‘, 0); |
В этом примере мы предоставляем полный список столбцов и используем синтаксис VALUES для вывода скалярных значений для вставки в таблицу.При желании мы можем вставить несколько строк с помощью этого синтаксиса, разделяя каждую строку запятой.
У нас также есть возможность исключать столбцы из списков столбцов и SELECT. Это можно использовать для столбцов, которые допускают NULL (и мы хотим оставить NULL), или для столбцов, для которых определены ограничения по умолчанию (и мы хотим, чтобы столбец принимал значение по умолчанию). В следующем примере показана вставка учетной записи, в которой мы опускаем столбец account_notes :
ВСТАВИТЬ В dbo.account (account_name, account_start_date, account_address, account_type, account_create_timestamp, is_active) VALUES (‘Initech’, ‘2/19/1999’, ‘4120 Freidrich 9000 L5. , GETUTCDATE (), 1); |
После двух вышеупомянутых вставок мы можем просмотреть полученные данные и отметить, что результаты соответствуют нашим ожиданиям:
SQL Server позволил нам опустить столбец account_notes и при этом присвоить его место NULL.Давайте добавим в этот столбец ограничение по умолчанию:
ИЗМЕНИТЬ ТАБЛИЦУ dbo.account ДОБАВИТЬ ОГРАНИЧЕНИЕ DF_account_account_notes ПО УМОЛЧАНИЮ («НЕ ПРЕДОСТАВЛЕНО») ДЛЯ account_notes; |
С ограничением по умолчанию для столбца мы можем протестировать еще один INSERT, где мы намеренно опускаем столбец account_notes :
ВСТАВИТЬ В dbo.account (account_name, account_start_date, account_address, account_type, account_create_timestamp, is_active) SELECT ‘Dinosaur Corp’, ‘1/1/2003’, ‘The Triassic Time Period’ , 9000 , GETUTCDATE (), 1; |
Результаты показывают нам, как выглядит новая строка в нашей таблице:
Мы видим, что значение по умолчанию из ограничения было применено к account_notes , как и ожидалось.Создание ограничения по умолчанию может быть полезно для обеспечения того, чтобы столбец мог быть НЕ ПУСТОЙ и ему всегда было присвоено значение. Это также полезно, когда мы хотим иметь столбец, которому обычно не назначается значение, но требуется его для приложения или цели отчетности. Ограничение по умолчанию никогда не должно использоваться для создания данных-заполнителей, поддельных или скрытых данных. Например, -1 — плохой выбор для целочисленного столбца, а 1/1/1900 — плохой выбор для столбца даты, поскольку каждый из них дает сбивающее с толку значение, которое не интуитивно понятно разработчику или тем, кто использует эти данные.
Основное преимущество вставки данных с явным списком столбцов заключается в том, что вы точно документируете, какие столбцы заполняются и какие данные помещаются в каждый столбец. Если столбец исключен из списка, он станет NULL. Если столбец NOT NULL без ограничения по умолчанию будет исключен из списка, будет выдана ошибка, подобная этой:
Точно так же, если вы случайно пропустите столбец из списка столбцов, вы получите следующую ошибку:
В результате явно предоставленный список столбцов затрудняет случайное исключение столбцов.
Однако у этого синтаксиса есть обратная сторона, а именно удобство обслуживания в сценариях, где схема таблицы часто меняется и есть желание всегда выбирать SELECT *. Если вы выгружаете данные в выходную таблицу и не заботитесь о порядке столбцов, типе или количестве, то необходимость всегда настраивать список столбцов в соответствии с деталями SELECT может быть проблемой и не стоит затраченных усилий.
Вставить данные в SQL Server без явного списка столбцов
Это приводит нас к альтернативному способу вставки данных в существующую таблицу, который должен делать это без списка столбцов.Вставка этой формы будет выглядеть так:
ВСТАВИТЬ В dbo.account SELECT «The Pokemon Company», «4/23/1998», «Roppongi Hills Mori Tower 8F, Tokyo, Japan», «LIVE», GETUTCDATE (), ‘Очень ценно. Они делают всех покемонов! », 1; |
Этот оператор выполняется успешно, несмотря на отсутствие списка столбцов.Когда SQL Server связывает этот запрос с его базовыми объектами, он извлекает список столбцов по порядку и применяет его к вставляемым данным. Если все совпадает, то все готово, иначе мы получим ошибку, аналогичную двум, которые мы видели ранее, которые указывают на несовпадающие списки столбцов.
Положительный момент (если мы хотим назвать это положительным моментом) этого подхода в том, что он быстрый и требует меньшего обслуживания, поскольку нет необходимости писать и поддерживать список столбцов со вставкой.Обратной стороной является то, что при несовпадении столбцов вы можете получить другое сообщение об ошибке. Рассмотрим следующий запрос:
INSERT INTO dbo.account SELECT ‘The Pokemon Company’, ‘4/23/1998’, ‘Roppongi Hills Mori Tower 8F, Tokyo, Japan’, GETUTCDATE (), ‘Очень ценно. Они делают всех покемонов! », 0; |
При выполнении мы получаем новое сообщение об ошибке:
В этом сценарии мы пропустили столбец, но поскольку эта таблица включает столбцы, допускающие NULL, SQL Server все равно пытался сопоставить столбцы таблицы, используя предоставленные нами данные, но не смог найти значимого сопоставления.
Из-за возможности сбивающих с толку ошибок и невозможности легко сопоставить столбцы с данными вставка в таблицу без предоставления списка столбцов не рассматривается как лучшая практика, и ее следует по возможности избегать. Я бы рекомендовал включать список столбцов во все операторы INSERT, если только у вас не будет очень уникального варианта использования, в котором удобство более простого синтаксиса перевешивает риск нарушения кода в будущем при изменении схемы таблицы.
Кроме того, список столбцов предоставляет пользователю четкую документацию относительно того, что вставляется и в какие столбцы будут помещены данные.Мы можем улучшить это дальше, если захотим, добавив псевдонимы ко всем вставленным столбцам:
INSERT INTO dbo.account (account_name, account_start_date, account_address, account_type, account_create_timestamp, account_notes, is_active) SELECT «Microsoft» AS account_name, 9000 account_start ‘ 75′ 4/4/4/4/ One Microsoft Way в Редмонде, Вашингтон ‘AS account_address, ‘ LIVE ‘AS account_type, GETUTCDATE () AS account_start_date, ‘ Они создают SQL Server.Спасибо!’ AS account_notes, 1 AS is_active; |
Добавление псевдонимов столбцов может показаться излишним, но при работе с более длинными операторами INSERT, динамическим SQL или сложными запросами добавленная документация может значительно помочь в написании, изменении и устранении неполадок в этих запросах. Вы также можете протестировать свой оператор вставки, выделив только список SELECT и выполнив его, который возвращает значения вместе с удобными заголовками столбцов:
В качестве альтернативы вы можете предоставить эту документацию в комментариях:
ВСТАВИТЬ В dbo.account (account_name, account_start_date, account_address, account_type, account_start_date, account_notes, is_active) SELECT «Microsoft», — account_name ‘4/4/1975’, — account_start_date ‘ Microsoft Way Редмонд, Вашингтон ‘, — account_address ‘ LIVE ‘, — account_type GETUTCDATE (), — account_start_date ‘ Они создают SQL Server. Спасибо! ‘, — account_notes 1; — is_active |
Это может быть хорошим способом документирования без корректировки запроса.Единственным недостатком является то, что вы теряете удобные имена столбцов, которые были продемонстрированы выше с помощью тестового SELECT. И то, и другое стоит дополнительных 30 секунд для включения в ваш код, поскольку они сэкономят гораздо больше времени в будущем, когда придет время изменить или устранить неполадки в этом коде.
Вставить данные в SQL Server с помощью SELECT INTO
Можно создать новый объект таблицы и выбрать в нем данные как часть одного оператора. Это может быть удобным способом избежать хлопот, связанных с предварительным определением таблицы и перечислением имен столбцов.Обычно это используется для заполнения временных таблиц, но его можно использовать для постоянных таблиц, если для этого требуется сценарий. SELECT INTO нельзя использовать для автоматического создания табличных переменных.
Запрос ниже показывает, как мы можем выполнить эту задачу быстро и эффективно:
SELECT ‘Ed Pollack’ AS имя_ разработчика, ‘SQL Server 2019 CTP1’ AS database_engine_of_choice, ‘Pizza’ AS food_choice, 10 AS spice_level INTO #developer_info; |
При выполнении временная таблица будет создана на лету с указанными именами столбцов.Когда мы запрашиваем таблицу, мы получаем следующие результаты:
Типы данных для столбцов автоматически выбираются SQL Server. Мы можем проверить их, запросив TempDB следующим образом:
SELECT table.name AS TableName, columns.name AS ColumnName, columns.max_length AS ColumnLength, types.name AS TypeName FROM TempDB.sys.tables ВНУТРЕННЕЕ СОЕДИНЕНИЕ TempDB.sys.columns ON tables.object_id = columns.object_id INNER JOIN TempDB.sys.types ON types.user_type_id = columns.user_type_id ###################################### developer_info% ‘; |
Результаты показывают столбцы, размер которых соответствует минимальным потребностям данных, которые я вставил:
Если бы я вставил несколько строк, размеры столбцов соответствовали бы минимальным размерам, необходимым для размещения всех этих данных.Это удивительно удобно, если предположить, что нам не нужно позже добавлять дополнительные данные во временную таблицу. Если мы это сделаем, нам нужно будет убедиться, что новые данные не превышают размеры столбцов, которые уже были определены.
Синтаксис SELECT INTO обеспечивает огромное удобство, когда мы хотим вставить в таблицу данные, которые могут сильно различаться от выполнения к выполнению или которые могут претерпевать изменения схемы достаточно часто, что затрудняет ведение списков столбцов.
При желании вы можете управлять типами данных. Давайте повторим наш пример выше, используя следующий TSQL:
SELECT CAST (‘Ed Pollack’ AS VARCHAR (50)) AS имя_разработчика, CAST (‘SQL Server 2019 CTP1’ AS VARCHAR (30)) AS database_engine_of_choice, CAST (‘Pizza’ AS VARCHAR (25 )) AS food_choice, CAST (10 AS DECIMAL (5,2)) AS spice_level INTO #developer_info; |
Когда мы консультируемся с системными представлениями, мы можем подтвердить, что типы данных были определены так, как мы хотели, а не как минимальные размеры, необходимые для поддержки данных, которые я создал:
Основным недостатком использования синтаксиса SELECT INTO является то, что результирующая таблица не будет иметь определенных индексов или ограничений.Если для таблицы требуется какая-либо дополнительная структура, ее нужно будет добавить постфактум. Для сценариев, где в этом нет необходимости, SELECT INTO предоставляет очень быстрый и удобный синтаксис, который может сократить код и улучшить ремонтопригодность за счет уменьшения количества мест, требующих изменения, когда базовая схема или определение данных претерпевают изменения.
SELECT INTO также может использоваться для общего оператора SELECT без дополнительных определений, таких как это:
ВЫБРАТЬ * INTO dbo.account_backup ОТ dbo.account; |
В очень коротком операторе TSQL мы создали новую постоянную таблицу и вставили в нее все содержимое dbo.account . Обратите внимание, что при использовании этого синтаксиса типы данных в результирующей таблице будут соответствовать исходной таблице в том виде, в котором они определены в настоящее время.
Вставка данных SQL Server с помощью хранимой процедуры или динамического SQL
Хранимые процедуры часто используются для возврата данных в приложения, отчеты или дополнительные сценарии TSQL для обработки.Результаты любой хранимой процедуры могут быть вставлены непосредственно в предопределенную таблицу следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 18 19 20 | CREATE TABLE #temp (SPID VARCHAR (100), STATUS VARCHAR (100), LOGIN VARCHAR (100), имя хоста VARCHAR (100), blkby VARCHAR (100), blkby VARCHAR (100) VARCHAR (100), команда VARCHAR (100), cputime VARCHAR (100), diskit VARCHAR (100), latbatch VARCHAR (100), имя программы VARCHAR (100), sp 100), Requestid VARCHAR (100)) INSERT INTO #temp EXEC sp_who2; ВЫБРАТЬ * ИЗ #temp ГДЕ dbname = ‘AdventureWorks2016CTP3’; DROP TABLE #temp; |
Этот сценарий мониторинга выполнит процедуру sp_who2, чтобы вернуть список текущих процессов в данной базе данных.По умолчанию эта хранимая процедура возвращает все сеансы, хотя могут быть предоставлены параметры для фильтрации по имени входа или идентификатору сеанса. Однако для фильтрации по базе данных в противном случае потребовалось бы вернуть все данные, а затем вручную удалить нерелевантные строки. Создав временную таблицу заранее и вставив результаты непосредственно в нее, мы можем фильтровать набор результатов по любым критериям, которые мы желаем. Для этой цели можно использовать любую таблицу, в том числе постоянные таблицы, а также табличные переменные.
Тот же синтаксис можно использовать для вставки результатов динамического SQL в таблицу, например:
DECLARE @sql_command NVARCHAR (MAX); DECLARE @account_type SYSNAME = ‘LIVE’; SELECT @sql_command = ‘ SELECT account_id FROM dbo.account WHERE account_type =’ » + @account_type + » ‘;’; СОЗДАТЬ ТАБЛИЦУ #id_list (account_id INT NOT NULL ПЕРВИЧНЫЙ КЛЮЧ КЛАСТЕРИРОВАН); INSERT INTO #id_list (account_id) EXEC sp_executesql @sql_command; ВЫБРАТЬ * ИЗ #id_list; ТАБЛИЦА УДАЛЕНИЯ #id_list; |
Конечным результатом этого кода является то, что мы используем sp_executesql для выполнения динамического SQL, помещая результаты непосредственно во временную таблицу.
В обоих этих сценариях мы смогли выполнить процедурный TSQL и вставить результаты непосредственно в существующую таблицу. SELECT INTO не поддерживается этим синтаксисом, но все остальное, что мы обсуждали до сих пор, работает с этим соглашением.
Вставить данные SQL Server со ВСТАВЛЕННЫМ ВЫВОДОМ
Дополнительный способ генерации данных — использование существующего оператора. Когда мы выполняем любую операцию записи, мы можем выводить данные до или после изменения в другую таблицу.Вот пример того, как это выглядит:
СОЗДАТЬ ТАБЛИЦУ #account_ids (account_id INT NOT NULL ПЕРВИЧНЫЙ КЛЮЧ КЛАСТЕРИРОВАН); UPDATE account SET is_active = 1 OUTPUT INSERTED.account_id INTO #account_ids FROM dbo.account WHERE account_type = ‘LIVE’; ВЫБРАТЬ * ИЗ #account_ids; DROP TABLE #account_ids; |
Целью выше является обновление всех учетных записей типа «LIVE», чтобы они были активными.Мы также хотим вернуть account_id для каждой обновленной учетной записи. Использование OUTPUT INSERTED позволяет нам выполнять обе задачи в одном решении на основе набора. Результаты показывают нам, какие идентификаторы были затронуты оператором обновления:
INSERTED будет содержать все столбцы в таблице в том виде, в котором они появляются после применения изменений. Точно так же DELETED будет содержать предыдущие версии. Мы можем смешивать и сочетать их для максимального эффекта:
CREATE TABLE #account_ids (account_id INT NOT NULL PRIMARY KEY CLUSTERED, is_active_previous BIT NOT NULL, is_active_current BIT NOT NULL); Учетная запись UPDATE SET is_active = 0 ВЫХОД ВСТАВЛЕН.account_id, DELETED.is_active, INSERTED.is_active INTO #account_ids FROM dbo.account WHERE account_type = ‘LIVE’; ВЫБРАТЬ * ИЗ #account_ids; DROP TABLE #account_ids; |
Результаты показывают, что мы захватили не только идентификаторы учетных записей, но также предыдущие и новые значения для флага is_active . Это огромное удобство, поскольку мы можем использовать OUTPUT INSERTED в операторах INSERT, DELETE, UPDATE и MERGE для быстрого извлечения данных до и после для использования в дополнительной обработке.
Это намного лучшее решение по сравнению с итерацией и / или использованием SCOPE_IDENTITY () и единственным простым способом захвата данных таким образом с таким небольшим кодом. OUTPUT INSERTED — отличный метод для получения данных до и после из операторов DML. Это также полезно для сбора списка строк, которые были изменены в данном операторе TSQL, чтобы мы могли предпринять дополнительные действия или сообщить о них по мере необходимости.
Какой метод лучше?
Поскольку существует множество методов вставки данных в SQL Server, первый вопрос, который мы зададим, — какой синтаксис нам следует использовать? Ответ будет зависеть от вашего варианта использования и, в частности, от того, что наиболее важно для данного приложения.Подводя итоги нашей работы на данный момент:
Используйте INSERT с явным списком столбцов для приложений, в которых списки столбцов, входные и выходные данные меняются нечасто. Это сценарии, в которых изменение обычно состоит из добавления столбцов или изменений в результате выпусков программного обеспечения. Списки столбцов также добавляют уровень защиты от логических ошибок, если столбец добавляется, удаляется или изменяется без обновления оператора INSERT. Возникшая ошибка — гораздо лучший результат, чем некорректная обработка данных.Этот синтаксис обычно считается оптимальным, поскольку он обеспечивает как документацию, так и защиту от непреднамеренных ошибок в случае изменения схемы в будущем.
INSERT без списка столбцов занимает нишу в сценариях, где столбцы неизвестны или часто меняются. Это может быть полезно в ETL, отчетах или сценариях с переходными данными, когда данные неструктурированы. Несмотря на это возможное приложение, я бы предпочел использовать SELECT INTO для этих приложений, поскольку они обеспечивают немного большую защиту от непреднамеренных ошибок с вашими данными.Альтернативой для покрытия необходимости вставки в уже существующую таблицу было бы использование SELECT INTO для создания временной структуры данных, а затем вставка из этих временных данных в постоянную таблицу с использованием формального списка столбцов.
SELECT INTO дает нам возможность быстро создать новую таблицу и выгрузить в нее данные с очень небольшой настройкой или кодированием. Для небольших наборов данных или тех, которые будут сканироваться полностью, это отличный способ переместить данные с минимальным TSQL и обслуживанием.Основным недостатком является невозможность включать индексы или ограничения в таблицу до тех пор, пока она не будет создана. Этот синтаксис должен создать новую таблицу, которая позволяет использовать временные таблицы в качестве цели для вставки данных.
OUTPUT INSERTED позволяет нам возвращать данные до, после или до и после оператора DML. Это чрезвычайно полезный синтаксис, у которого нет внутренних недостатков. Это отличная альтернатива итерациям, функциям или триггерам, которые могут пытаться выполнять те же задачи.Синтаксис относительно прост и может применяться к любым элементам данных до или после данного изменения. Вы даже можете включить данные, на которые оператор DML не влияет напрямую, но которые были объединены для использования в запросе!
Заключение
Есть много способов вставить данные в SQL Server, но не все они были созданы одинаковыми. Выбор правильного синтаксиса может существенно повлиять на производительность, документацию и ремонтопригодность. В этой статье приводится сравнение различных синтаксисов, а также плюсы, минусы и демонстрации каждого из них.
Всегда учитывайте свое приложение при написании кода и корректируйте свой стиль в зависимости от того, как часто предполагается изменение схемы и кода. Статические и редко изменяемые схемы и приложения могут позволить себе иметь жестко запрограммированные операторы INSERT со столбцами, псевдонимами и / или справочной документацией, чтобы их было легко читать и поддерживать.
Для схемы или бизнес-потребностей, которые часто меняются, SELECT INTO или исключение списка столбцов из INSERT может обеспечить большую гибкость в тех местах, где код может значительно выиграть от этого.
Наличие множества опций в нашем распоряжении позволяет нам принимать более обоснованные решения, когда необходим разумный выбор, и помогает нам писать лучший код, который заставит будущих разработчиков ценить нас гораздо больше, когда он обновляется и поддерживается!
Ссылки и дополнительная литература
Эд имеет 20-летний опыт работы в области администрирования баз данных и систем, он увлечен оптимизацией производительности, проектированием баз данных и ускорением работы.Он выступал на многих субботах SQL, 24 Hours of PASS и саммите PASS. Это привело его к организации субботы SQL в Олбани, которая стала ежегодным мероприятием для столичного региона Нью-Йорка.
В свободное время Эд любит видеоигры, научную фантастику и фэнтези, путешествовать и быть настолько большим компьютерщиком, насколько его друзья терпят.
Посмотреть все сообщения Ed Pollack
Последние сообщения Ed Pollack (посмотреть все)
Как вставить Microsoft SQL | Small Business
Microsoft SQL Server обеспечивает быструю доставку запросов и надежную доступность для предприятий любого размера.Вставка ваших данных в базу данных может быть гораздо более универсальной и эффективной, чем их автономное хранение в документе или электронной таблице. Microsoft SQL Server использует расширение Transact-SQL или T-SQL для совместимости между различными пользовательскими интерфейсами. Команда INSERT ведет себя так же, как и другие серверы SQL, и вы можете добавлять строки базы данных с переменными из других таблиц или с помощью оператора SQL SELECT.
Нажмите кнопку «Пуск» и запустите «Microsoft SQL Server». Откройте меню «Имя сервера» и выберите сервер, к которому вы хотите подключиться.Нажмите «Подключиться», чтобы открыть обозреватель объектов.
Щелкните правой кнопкой мыши имя сервера в дереве базы данных в левой части окна. Щелкните «Новый запрос», чтобы открыть окно командной строки для ввода операторов SQL.
Добавьте строку, подобную следующей, чтобы указать таблицу, в которую вы вставляете запись, а также имена вставляемых столбцов:
INSERT INTO client_accounts (client_number, last_name, first_name, address)
Укажите значения столбца строки, которую вы вставляете, с помощью оператора VALUES, например следующего:
VALUES (12345, ‘Jones’, ‘Melissa’, ‘543 W 21st Street’) GO
Выполните оператор с ключевым словом GO , аналогично терминальной точке с запятой при работе с другими серверами баз данных.
Используйте ключевое слово SELECT вместо VALUES для вставки столбцов из другой таблицы в базу данных. Поместите имя столбца в одинарные кавычки. Например, введите следующую команду:
INSERT INTO client_accounts ВЫБРАТЬ «client_number» 12345 FROM other_table_name GO
Замените «other_table_name» именем таблицы, из которой нужно выбрать.
Ресурсы
Советы
- Используйте команду BEGIN TRANSACTION, чтобы создать точку восстановления для любых изменений, которые вы вносите в базу данных.Например, введите следующее:
- BEGIN TRANSACTION insert_transaction
- GO
- После внесения изменений используйте ключевое слово ROLLBACK или COMMIT, чтобы сохранить или отменить изменения, как показано в следующем коде:
- ROLLBACK TRANSACTION insert_transaction
- GO
Writer Bio
Дэвид Уэйн пишет с 2010 года, в нескольких региональных газетах Техаса появляются колонки о технологиях. Уэйн окончил Хьюстонский университет в 2005 году, получив степень бакалавра искусств в области коммуникаций.
Работа с оператором INSERT в SQL Server
Оператор INSERT позволяет добавлять одну или несколько строк в таблицу или представление в базе данных SQL Server. Этот оператор является одним из операторов основного языка модификации данных (DML), доступных в Transact-SQL, наряду с UPDATE, MERGE и DELETE. Вы можете использовать оператор INSERT для добавления данных, которые вы определяете специально, или вы можете добавить данные, которые вы извлекаете из других таблиц или представлений. Вы также можете включить предложение OUTPUT в свой оператор INSERT, чтобы фиксировать результаты оператора для целей аудита или проверки.
В этой статье я объясню, как использовать оператор INSERT для добавления данных в таблицы SQL Server. Примеры, которые я показываю, основаны на образце базы данных AdventureWorks2008, установленном на локальном экземпляре SQL Server 2008. Однако вы можете запустить большинство этих примеров в базе данных AdventureWorks в SQL Server 2005 с небольшими изменениями, такими как изменение имени базы данных. . Где это уместно, я отмечаю, какие функции не поддерживаются в 2005 году.
ПРИМЕЧАНИЕ: Одно из представлений, которые я упоминаю в базе данных AdventureWorks2008 (представление SalesPerson), включает столбец BusinessEntityID.Этот столбец называется столбцом SalesPersonID в базе данных AdventureWorks.
В базовом операторе INSERT вы должны указать имя целевой таблицы и значения данных, которые вы хотите вставить в эту таблицу. При необходимости вы должны дополнить это имя таблицы именем сервера, базы данных или схемы.
Чтобы продемонстрировать, как создать базовый оператор INSERT, я сначала использовал следующий код для создания таблицы SalesStaff1 в базе данных AdventureWorks2008:
ИСПОЛЬЗОВАТЬ AdventureWorks2008; ЕСЛИ OBJECT_ID (‘SalesStaff1’, ‘U’) НЕ ПУСТОЙ DROP TABLE SalesStaff1; СОЗДАТЬ ТАБЛИЦУ SalesStaff1 ( StaffID INT NOT NULL PRIMARY KEY, FirstName NVARCHAR (30) NOT NULL, LastName NVARCHAR (30) NOT NULL ); |
Сама таблица довольно проста, как и оператор INSERT, необходимый для добавления строки данных.Для этого оператора требуется ключевое слово INSERT, имя целевой таблицы, ключевое слово VALUES и значения для вставки, как показано в следующем примере:
ВСТАВИТЬ В ЗНАЧЕНИЯ SalesStaff1 (1, «Стивен», «Цзян»); |
Обратите внимание, что оператор начинается с ключевого слова INSERT, за которым следует ключевое слово INTO. Ключевое слово INTO необязательно. Часто вы увидите, что это используется.Часто вы этого не сделаете. После ключевого слова INSERT и необязательного ключевого слова INTO вы указываете имя целевой таблицы, которой в данном случае является SalesStaff1.
Затем вы указываете ключевое слово VALUES, а затем сами значения. Обратите внимание, что значения заключены в круглые скобки и разделены запятыми. Кроме того, строковые значения заключаются в одинарные кавычки. Значения вставляются в таблицу в том порядке, в котором они указаны в предложении. Это означает, что значения должны быть в том же порядке, что и столбцы, определенные в таблице.В этом случае 1 вставляется в первый столбец таблицы (StaffID), Stephen вставляется во второй столбец (FirstName), а Jiang вставляется в третий столбец (LastName).
Вот и все, что нужно для вставки строки в таблицу. Однако, как это часто бывает, вы можете захотеть добавить несколько строк в таблицу в одном операторе. До SQL Server 2008 это было невозможно, но теперь оператор INSERT позволяет указать несколько строк, как показано в следующем примере:
ВСТАВИТЬ SalesStaff1 ЗНАЧЕНИЯ (2, «Майкл», «Блайт»), (3, «Линда», «Митчелл»), (4, «Джиллиан», «Карсон»), (5, «Гарретт», «Варгас»); |
Как видите, вы все равно должны указать ключевое слово INSERT, имя целевой таблицы и ключевое слово VALUES.Однако вместо одного набора круглых скобок теперь у вас есть набор для каждой строки, которую нужно вставить в таблицу. Затем наборы значений разделяются запятыми. Теперь, когда вы запустите оператор, все четыре строки будут добавлены в таблицу SalesStaff1.
Примеры в предыдущем разделе — это простейшие операторы INSERT. Они предполагают, что вы добавите по одному значению в каждый столбец таблицы для каждой строки, которую планируете вставить. Однако это не всегда так просто. Во многих случаях вам нужно вставить значения в определенные столбцы, но не во все столбцы.Например, если у вас есть столбец IDENTITY, вы, возможно, не захотите вставлять в него значение, а вместо этого разрешите ядру базы данных автоматически сгенерировать следующее значение. Однако для оператора INSERT, использованного в предыдущих примерах, требуется одно значение для каждого столбца. Если вы не укажете подходящее значение для каждого столбца, вы получите ошибку.
Для решения этой проблемы оператор INSERT поддерживает дополнительный компонент, который позволяет указать, какие столбцы должны получать значения.Указанные вами значения затем вставляются в эти столбцы. Предполагается, что столбцы, которые не указаны, генерируют свои собственные значения, как в случае со столбцами IDENTITY, вычисляемыми столбцами или столбцами, для которых было определено значение по умолчанию.
Например, следующий код создает таблицу SalesStaff2, которая включает столбцы, не требующие явного добавления значений:
ИСПОЛЬЗОВАТЬ AdventureWorks2008; ЕСЛИ OBJECT_ID (‘SalesStaff2’, ‘U’) НЕ ПУСТОЙ DROP TABLE SalesStaff2; СОЗДАТЬ ТАБЛИЦУ SalesStaff2 ( StaffID INT NOT NULL IDENTITY PRIMARY KEY, StaffGUID UNIQUEIDENTIFIER NULL, Имя NVARCHAR Последнее (30) NOT NULL AS4, NULL NULL (FirstName + » + LastName), ModifiedDate DATETIME NOT NULL ПО УМОЛЧАНИЮ GETDATE () ); |
Как видите, StaffID — это столбец IDENTITY, FullName — это вычисляемый столбец, а ModifiedDate был определен со значением по умолчанию (полученным с помощью функции GETDATE).Теперь давайте посмотрим на оператор INSERT, который предоставляет значения для трех других столбцов: StaffGUID, FirstName, LastName:
.
ВСТАВИТЬ В SalesStaff2 (StaffGUID, FirstName, LastName) ЗНАЧЕНИЯ (NEWID (), ‘Stephen’, ‘Jiang’); ВЫБРАТЬ StaffID, StaffGUID, FullName, ModifiedDate FROM SalesStaff2; |
Обратите внимание, что я добавляю список столбцов после того, как укажу ключевые слова INSERT INTO и имя целевой таблицы.Столбцы заключаются в круглые скобки и разделяются запятыми. Данные, которые я указываю в предложении VALUES, должны соответствовать этим столбцам. В этом случае предложение VALUES включает три значения. Первая — это функция NEWID, которая генерирует GUID для столбца StaffGUID. Второе значение, Стивен, , вставляется в столбец FirstName, а третье значение, Jiang, вставляется в столбец LastName.
Как видите, я не включаю имена или значения столбцов ни в один из столбцов, значения которых генерируются автоматически.Я могу включить значение в столбец StaffID, если база данных настроена так, чтобы я мог переопределять значения IDENTIY. Я также могу включить значение, чтобы переопределить значение ModifiedDate по умолчанию. В любом случае я должен включить имя столбца после предложения INSERT и включить значение в предложение VALUES в правильном порядке.
Как вы, несомненно, заметили, в приведенном выше примере я добавил оператор SELECT после оператора INSERT. Оператор возвращает значения, которые были автоматически сгенерированы при вставке строк, как показано в следующих результатах:
StaffID | StaffGUID | FullName | Изменено Дата |
1 | C96716E5-2DEE-4887-80C9-F0C3A1D38B98 | Стивен Цзян | 21 сентября 2010 г., 07:56:59.487 |
Вот и все, что нужно для добавления данных в определенные столбцы. Вы просто указываете имена столбцов, которые должны принимать значения, а затем указываете эти значения. Вы можете указать имена столбцов в любом порядке. Просто убедитесь, что данные в предложении VALUES соответствуют порядку столбцов. Теперь давайте посмотрим, что происходит, когда вы не определяете явно свои ценности.
В предыдущих примерах предложение VALUES включает набор значений, заключенных в круглые скобки и разделенных запятыми.Но не всегда нужно указывать значения явно. Вместо этого вы можете получить значения с помощью оператора SELECT или хранимой процедуры. Чтобы продемонстрировать, как это работает, я сначала создал таблицу SalesStaff3, показанную в следующем коде:
ИСПОЛЬЗОВАТЬ AdventureWorks2008; ЕСЛИ OBJECT_ID (‘SalesStaff3’, ‘U’) НЕ ПУСТОЙ DROP TABLE SalesStaff3; СОЗДАТЬ ТАБЛИЦУ SalesStaff3 ( StaffID INT NOT NULL PRIMARY KEY, FullName NVARCHAR (60) NOT NULL, ModifiedDate DATETIME NOT NULL DEFAULT GETDATE ) ; |
Предположим, я хочу вставить данные в таблицу SalesStaff3, полученную из Sales.Представление vSalesPerson в базе данных AdventureWorks2008. Вместо указания предложения VALUES я могу указать оператор SELECT, который извлекает данные непосредственно из представления vSalesPerson, как показано в следующем примере:
ВСТАВИТЬ SalesStaff3 (StaffID, FullName) SELECT TOP 5 BusinessEntityID, FirstName + » + LastName AS FullName FROM Sales.vSalesPerson ORDER BY BusinessEntityID; ВЫБРАТЬ * ОТ SalesStaff3; |
Вы можете заменить предложение VALUES любым допустимым оператором SELECT, который возвращает соответствующие данные.В этом случае я получаю значения BusinessEntityID и имена пяти лучших продавцов на основе BusinessEntityID. После оператора INSERT я запускаю оператор SELECT, чтобы подтвердить, что данные были вставлены в таблицу SalesStaff3, как показано в следующих результатах:
StaffID | FullName | Изменено Дата |
274 | Стивен Цзян | 21 сентября 2010, 08:15:48.927 |
275 | Майкл Блайт | 21.09.2010 08:15: 48.927 |
276 | Линда Митчелл | 21.09.2010 08:15: 48.927 |
277 | Джиллиан Карсон | 21.09.2010 08:15: 48.927 |
278 | Гаррет Варгас | 21 сентября 2010, 08:15:48.927 |
Оператор SELECT, который используется в операторе INSERT, может ссылаться на общее табличное выражение (CTE), а также на таблицу или представление, если этот CTE предшествует оператору INSERT (в отличие от того, чтобы быть частью самого оператора SELECT ). Например, в следующем примере я сначала определяю CTE, а затем определяю оператор INSERT, который извлекает данные из CTE с помощью оператора SELECT:
С cteSalesStaff (StaffID, FullName) AS ( SELECT BusinessEntityID, FirstName + » + LastName AS FullName ИЗ отдела продаж.vSalesPerson ГДЕ BusinessEntityID МЕЖДУ 279 И 283 ) ВСТАВИТЬ SalesStaff3 (StaffID, FullName) SELECT StaffID, FullName FROM cteSalesStaff; ВЫБРАТЬ * ОТ SalesStaff3 ГДЕ StaffID МЕЖДУ 279 И 283; |
Обратите внимание, что CTE извлекает данные из представления vSalesPerson. Оператор SELECT в операторе INSERT затем извлекает содержимое CTE, как если бы он извлекал данные непосредственно из таблицы.Затем эти данные вставляются в таблицу SalesStaff3. Последний оператор SELECT подтверждает, что данные были добавлены, как показано в следующих результатах:
StaffID | FullName | Изменено Дата |
279 | Цви Рейтер | 2010-09-21 08: 26: 04.340 |
280 | Памела Ансман-Вулф | 21 сентября 2010, 08:26:04.340 |
281 | Шу Ито | 2010-09-21 08: 26: 04.340 |
282 | Хосе Сараива | 2010-09-21 08: 26: 04.340 |
283 | Дэвид Кэмпбелл | 2010-09-21 08: 26: 04.340 |
Вместо использования оператора SELECT для извлечения данных вы можете вызвать хранимую процедуру в своем операторе INSERT.Например, следующая хранимая процедура spSalesStaff извлекает данные из представления vSalesPerson:
ИСПОЛЬЗОВАТЬ AdventureWorks2008; ЕСЛИ OBJECT_ID (‘spSalesStaff’, ‘P’) НЕ ПУСТОЙ ПРОЦЕДУРА УДАЛЕНИЯ spSalesStaff; GO СОЗДАТЬ ПРОЦЕДУРУ spSalesStaff AS SELECT BusinessEntityID, FirstName + » + LastName AS FullName ИЗ продаж.vSalesPerson ГДЕ BusinessEntityID МЕЖДУ 284 И 288; |
Затем я могу вызвать эту хранимую процедуру из оператора INSERT, как показано в следующем примере:
ВСТАВИТЬ SalesStaff3 (StaffID, FullName) EXEC spSalesStaff; ВЫБРАТЬ * ОТ SalesStaff3 ГДЕ StaffID МЕЖДУ 284 И 288; |
Обратите внимание, что вместо предложения VALUES или оператора SELECT я включил оператор EXECUTE (EXEC), который вызывает хранимую процедуру spSalesStaff.Когда я запускаю оператор INSERT, процедура выполняется, и возвращенные данные вставляются в таблицу SalesStaff3. Следующие результаты подтверждают, что данные были вставлены:
StaffID | FullName | Изменено Дата |
284 | Тете Менса-Аннан | 21 сентября 2010, 08:36:30.207 |
285 | Сайед Аббас | 21.09.2010 08: 36: 30.207 |
286 | Линн Цофлиас | 21.09.2010 08: 36: 30.207 |
287 | Эми Альбертс | 21.09.2010 08: 36: 30.207 |
288 | Рэйчел Вальдес | 21 сентября 2010, 08:36:30.207 |
Как видите, вставка данных с помощью оператора SELECT или хранимой процедуры обеспечивает простой способ добавления нескольких строк в таблицу без необходимости явно определять каждое значение.
Начиная с SQL Server 2005, операторы DML поддерживают предложение OUTPUT, которое позволяет вывести измененную таблицу в другую таблицу или переменную. В случае оператора INSERT вы можете использовать предложение OUTPUT для отслеживания данных, которые вставляются в вашу таблицу.Например, следующий оператор INSERT использует предложение OUTPUT для вывода вставленных значений в табличную переменную:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 18 19 | DECLARE @InsertOutput TABLE ( StaffID INT, FullName VARCHAR (60) ); ВСТАВИТЬ В SalesStaff3 (StaffID, FullName) ВЫВОД ВСТАВЛЕН.StaffID, INSERTED.FullName INTO @InsertOutput SELECT BusinessEntityID, FirstName + » + LastName AS FullName FROM Sales.vSalesPerson WHERE BusinessEntity>; ВЫБРАТЬ * ОТ SalesStaff3 ГДЕ StaffID> 288; ВЫБРАТЬ * ИЗ @InsertOutput; |
Сначала я объявляю переменную @InsertOutput и настраиваю ее с двумя столбцами: StaffID и FullName.Эти два столбца соответствуют тем же двум столбцам в таблице SalesStaff3, которые использовались в примерах в предыдущем разделе.
После объявления переменной я определяю оператор INSERT, который использует оператор SELECT для извлечения данных из представления vSalesPerson. Оператор INSERT также включает предложение OUTPUT, которое следует за предложением INSERT и списком столбцов. Предложение OUTPUT захватывает данные, вставленные в столбцы StaffID и FullName, и сохраняет их в переменной @InsertOutput.
ПРИМЕЧАНИЕ: Для полного обсуждения предложения OUTPUT см. Статью Simple-Talk «Реализация предложения OUTPUT в SQL Server 2008» (http://www.simple-talk.com/sql/learn-sql-server / реализация-предложение-вывода-в-sql-server-2008 /).
После оператора INSERT я включаю оператор SELECT, чтобы убедиться, что данные были вставлены в таблицу SalesStaff3. Оператор возвращает следующие результаты:
StaffID | FullName | Изменено Дата |
289 | Джэ Пак | 21 сентября 2010, 08:49:03.983 |
290 | Ранджит Варки Чудукатил | 21.09.2010 08:49: 03.983 |
Я также включаю второй оператор SELECT для извлечения содержимого @InsertOutput после того, как выведенные данные были сохранены в переменной. В следующей таблице показано содержимое переменной:
StaffID | FullName |
289 | Джэ Пак |
290 | Ранджит Варки Чудукатил |
Вот и все, что нужно для реализации предложения OUTPUT в вашем операторе INSERT.Фактически, это все, что нужно для работы с оператором INSERT. Однако обратите внимание, что оператор INSERT поддерживает несколько других функций. Поэтому обязательно ознакомьтесь с разделом «INSERT (Transact-SQL)» в электронной документации по SQL Server. Вы также можете найти дополнительные примеры инструкции INSERT в разделе «Примеры INSERT (Transact-SQL)» в электронной документации по SQL Server.
Мы предоставили полноразмерные железнодорожные схемы для пунктов INSERT и OUTPUT в виде файлов PDF, которые можно скачать ниже.
ssms — Как лучше всего автоматически генерировать инструкции INSERT для таблицы SQL Server?
Выше есть много хороших сценариев для генерации операторов вставки, но я попытался сделать один из моих собственных, чтобы сделать его максимально удобным для пользователя, а также чтобы иметь возможность выполнять операторы UPDATE. + упаковать результат в готовые файлы .sql, которые можно сохранить по дате.
Он принимает в качестве входных данных ваш обычный оператор SELECT с предложением WHERE, а затем выводит список операторов Insert и операторов обновления.Вместе они образуют своего рода IF NOT EXISTS () INSERT ELSE UPDATE. Это также удобно, когда есть необновляемые столбцы, которые нужно исключить из последнего оператора INSERT / UPDATE.
Еще одна вещь, которую может выполнять нижеприведенный сценарий: он может даже обрабатывать INNER JOINs с другими таблицами в качестве оператора ввода для сохраненной процедуры. Он может быть удобен в качестве инструмента управления релизами для бедняков, который находится прямо у вас под рукой, когда вы весь день набираете SQL-операторы SELECT.
исходное сообщение: Создать оператор UPDATE в SQL Server для конкретной таблицы
СОЗДАТЬ ПРОЦЕДУРУ [dbo].[sp_generate_updates] (
@fullquery nvarchar (max) = '',
@ignore_field_input nvarchar (MAX) = '',
@PK_COLUMN_NAME nvarchar (MAX) = ''
)
В КАЧЕСТВЕ
ВКЛЮЧИТЬ NOCOUNT
ВКЛЮЧИТЬ QUOTED_IDENTIFIER
/ *
- Для стандартного ИСПОЛЬЗОВАНИЯ: (где пункт является обязательным)
EXEC [sp_generate_updates] 'выберите * из dbo.mytable, где mytext =' '1' ''
ИЛИ
ВЫКЛЮЧИТЬ QUOTED_IDENTIFIER
EXEC [sp_generate_updates] "выберите * из dbo.mytable, где mytext = '1'"
- Для игнорирования определенных столбцов (игнорировать в SQL-запросах UPDATE и INSERT)
EXEC [sp_generate_updates] 'выберите * из dbo.mytable, где 1 = 1 ',' Столбец01, Столбец02 '
- Только для обновлений без инструкции вставки (замените *)
EXEC [sp_generate_updates] 'выберите Column01, Column02 из dbo.mytable, где 1 = 1'
- Для таблиц без первичного ключа: построить ключ в третьей переменной.
EXEC [sp_generate_updates] 'выберите * из dbo.mytable, где 1 = 1', '', 'your_chosen_primary_key_Col1, key_Col2'
- Для сложных обновлений с JOINED таблицами
EXEC [sp_generate_updates] 'выберите o1.Имя, o1.category, o2.name + '_hello_world' как #name
с ночевки o1
внутреннее соединение на ночь, установка o2 на o1.name = o2.name
где o1.name как '% appserver%'
(ЗАМЕТКА выше: использование # перед именем столбца (поэтому #abc) может выполнить обновление этого имени столбца (abc) с любым столбцом из внутренней объединенной таблицы, где вы используете псевдоним #abc)
------------- README для более глубокого заинтересованного человека:
Целью хранимой процедуры является получение обновлений из простых операторов SQL SELECT.Он сделан не простым, но быстрым и мощным. Как всегда => власть - ничто без контроля, поэтому проверьте перед выполнением.
Его сила также заключается в том, что вы можете делать операторы вставки, поэтому в сочетании дает вам возможность «IF NOT EXISTS () INSERT».
Скрипты работают там, где есть первичные ключи или столбцы идентификаторов в таблице, которую вы хотите обновить (/ или сделать вставки).
Он также будет работать, когда не существует (-ов) столбца первичных ключей / идентификаторов, и вы определяете их самостоятельно.Но тогда будьте осторожны (могут возникнуть повторяющиеся совпадения). Если у таблицы есть первичный ключ, он будет использоваться всегда.
Скрипт работает с реальной временной таблицей, созданной на лету (необходимы СООТВЕТСТВУЮЩИЕ ПРАВА), чтобы поместить значения внутрь скрипта, затем добавить 3 столбца для построения «вставить в tableX (...) values ()» и 2 заявление об обновлении.
Мы работаем с временными структурами, такими как «where columnname = {Columnname}», а затем обновляем этот искушаемый объект для значений столбцов, найденных в той же строке.пример "where columnname = {Columnname}" для даты рождения превращается в "where Birthdate = {Birthdate}", а затем мы находим значение даты рождения в этой строке во временной таблице.
Таким образом, утверждение становится «где дата рождения = {19800417}».
Наслаждайтесь выпуском скриптов прямо сейчас ... Питера ван Недеркасселя - бесплатное ПО "CC BY-SA" (+ использование на свой страх и риск)
* /
ЕСЛИ OBJECT_ID ('tempdb .. # ignore', 'U') НЕ ЯВЛЯЕТСЯ NULL DROP TABLE #ignore
DECLARE @stringsplit_table TABLE (col nvarchar (255), dtype nvarchar (255)) - таблица для хранения первичных ключей или ключа идентификации
DECLARE @PK_condition nvarchar (512), - заполнитель для WHERE pk_field1 = pk_value1 AND pk_field2 = pk_value2 AND...
@pkstring NVARCHAR (512), - строка для хранения первичных ключей или идентификационного ключа
@table_name nvarchar (512), - (слева) имя таблицы, включая схему
@table_N_where_clause nvarchar (max), - имя таблицы
@table_alias nvarchar (512), - содержит (левый) псевдоним таблицы, если он доступен, иначе @table_name
@table_schema NVARCHAR (30), - схема @table_name
@ update_list1 NVARCHAR (MAX), - заполнитель для раздела SET полей обновления
@ update_list2 NVARCHAR (MAX), - заполнитель для раздела полей SET значения обновления, поступающего из других таблиц в объединении, кроме основной таблицы для обновления => обновление базовой таблицы возможно с внутренним объединением
@list_all_cols BIT = 0, - заполнитель для значений для вставки в таблицу команда VALUES
@select_list NVARCHAR (MAX), - заполнитель для полей SELECT (левой) таблицы
@COLUMN_NAME NVARCHAR (255), - будет содержать имена столбцов (левой) таблицы
@sql NVARCHAR (MAX), - переменная оператора sql
@getdate NVARCHAR (17), - преобразовать getdate () в YYYYMMDDHHMMSSMMM
@tmp_table NVARCHAR (255), - будет содержать имя физической временной таблицы
@pk_separator NVARCHAR (1), - разделитель, используемый в @PK_COLUMN_NAME, если он указан (только проверка очевидных,; | -)
@COLUMN_NAME_DATA_TYPE NVARCHAR (100), - необходимо для операторов вставки для преобразования в правую текстовую строку
@own_pk BIT = 0 - проверить, есть ли в таблице PK (0) или будет использоваться предоставленный PK (1)
set @ ignore_field_input = replace (replace (replace (@ignore_field_input, '', ''), '[', ''), ']', '')
set @ PK_COLUMN_NAME = replace (replace (replace (@PK_COLUMN_NAME, '', ''), '[', ''), ']', '')
- сначала мы удаляем все переводы строки из пользовательского запроса
set @ fullquery = replace (replace (replace (@ fullquery, char (10), ''), char (13), ''), '', '')
установить @ table_N_where_clause = @ fullquery
если charindex ('заказ по', @table_N_where_clause)> 0
print 'ВНИМАНИЕ: ЗАКАЗ НЕ РАЗРЕШЕН В ОБНОВЛЕНИИ... '
если @PK_COLUMN_NAME <> ''
выберите 'ПРЕДУПРЕЖДЕНИЕ: ЕСЛИ вы выбираете свои собственные первичные ключи, дважды убедитесь, прежде чем выполнять инструкции обновления ниже !! '
--print @table_N_where_clause
если charindex ('select', @table_N_where_clause) = 0
set @ table_N_where_clause = 'выбрать * из' + @table_N_where_clause
если charindex ('select', @table_N_where_clause)> 0
exec (@table_N_where_clause)
установить @ table_N_where_clause = rtrim (ltrim (substring (@ table_N_where_clause, CHARINDEX ('from', @table_N_where_clause) +6, 4000)))
--print @table_N_where_clause
установить @ table_name = left (@ table_N_where_clause, CHARINDEX ('', @table_N_where_clause) -1)
IF CHARINDEX ('где', @table_N_where_clause)> 0 SELECT @table_alias = LTRIM (RTRIM (REPLACE (REPLACE (SUBSTRING (@ table_N_where_clause, 1, CHARINDEX ('where', @table_N_where_clause) -1), '(nolock)', ''), @ имя_таблицы, '')))
IF CHARINDEX ('join', @table_alias)> 0 SELECT @table_alias = SUBSTRING (@table_alias, 1, CHARINDEX (', @table_alias) -1) - до следующего пробела
ЕСЛИ LEN (@table_alias) = 0 ВЫБРАТЬ @table_alias = @table_name
IF (charindex ('*', @fullquery)> 0 или charindex (@ table_alias + '.* ', @fullquery)> 0) установить @ list_all_cols = 1
/ *
печать @fullquery
печать @table_alias
печать @table_N_where_clause
print @table_name
* /
- Подготовить состояние ПК
ВЫБЕРИТЕ @table_schema = CASE WHEN CHARINDEX ('.', @ Table_name)> 0 THEN LEFT (@table_name, CHARINDEX ('.', @ Table_name) -1) ELSE 'dbo' END
ВЫБЕРИТЕ @PK_condition = ISNULL (@PK_condition + 'И', '') + QUOTENAME ('pk _' + COLUMN_NAME) + '=' + QUOTENAME ('pk _' + COLUMN_NAME, '{')
ОТ INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY (OBJECT_ID (CONSTRAINT_SCHEMA + '.' + QUOTENAME (CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
И ИМЯ ТАБЛИЦЫ = ЗАМЕНИТЬ (@ имя_таблицы, @ схема_таблицы + '.', '')
И TABLE_SCHEMA = @table_schema
ВЫБЕРИТЕ @pkstring = ISNULL (@pkstring + ',', '') + @table_alias + '.' + QUOTENAME (COLUMN_NAME) + 'AS pk_' + COLUMN_NAME
ОТ INFORMATION_SCHEMA.KEY_COLUMN_USAGE i1
ГДЕ OBJECTPROPERTY (OBJECT_ID (i1.CONSTRAINT_SCHEMA + '.' + QUOTENAME (i1.CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
И i1.TABLE_NAME = REPLACE (@ table_name, @ table_schema + '.', '')
И i1.TABLE_SCHEMA = @table_schema
- если первичных ключей не существует, мы пробуем использовать столбцы идентификаторов
ЕСЛИ @PK_condition равно нулю SELECT @PK_condition = ISNULL (@PK_condition + 'AND', '') + QUOTENAME ('pk _' + COLUMN_NAME) + '=' + QUOTENAME ('pk _' + COLUMN_NAME, '{')
ИЗ INFORMATION_SCHEMA.COLUMNS
ГДЕ COLUMNPROPERTY (object_id (TABLE_SCHEMA + '.'+ TABLE_NAME), COLUMN_NAME,' IsIdentity ') = 1
И ИМЯ ТАБЛИЦЫ = ЗАМЕНИТЬ (@ имя_таблицы, @ схема_таблицы + '.', '')
И TABLE_SCHEMA = @table_schema
ЕСЛИ @pkstring имеет значение NULL SELECT @pkstring = ISNULL (@pkstring + ',', '') + @table_alias + '.' + QUOTENAME (COLUMN_NAME) + 'AS pk_' + COLUMN_NAME
ИЗ INFORMATION_SCHEMA.COLUMNS
ГДЕ COLUMNPROPERTY (object_id (TABLE_SCHEMA + '.' + TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
И ИМЯ ТАБЛИЦЫ = ЗАМЕНИТЬ (@ имя_таблицы, @ схема_таблицы + '.',' ')
И TABLE_SCHEMA = @table_schema
- То же, но в виде таблицы
ВСТАВИТЬ @stringsplit_table
ВЫБЕРИТЕ 'pk _' + i1.COLUMN_NAME как col, i2.DATA_TYPE как dtype
ОТ INFORMATION_SCHEMA.KEY_COLUMN_USAGE i1
внутреннее соединение INFORMATION_SCHEMA.COLUMNS i2
на i1.TABLE_NAME = i2.TABLE_NAME И i1.TABLE_SCHEMA = i2.TABLE_SCHEMA
WHERE OBJECTPROPERTY (OBJECT_ID (i1.CONSTRAINT_SCHEMA + '.' + QUOTENAME (i1.CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
И i1.ТАБЛИЦА = ЗАМЕНИТЬ (@ имя_таблицы, @ схема_таблицы + '.', '')
И i1.TABLE_SCHEMA = @table_schema
- если первичных ключей не существует, мы пробуем использовать столбцы идентификаторов
ЕСЛИ 0 = (выберите количество (*) из @stringsplit_table) INSERT INTO @stringsplit_table
ВЫБЕРИТЕ 'pk _' + i2.COLUMN_NAME как col, i2.DATA_TYPE как dtype
ИЗ INFORMATION_SCHEMA.COLUMNS i2
ГДЕ COLUMNPROPERTY (object_id (i2.TABLE_SCHEMA + '.' + I2.TABLE_NAME), i2.COLUMN_NAME, 'IsIdentity') = 1
И i2.ТАБЛИЦА = ЗАМЕНИТЬ (@ имя_таблицы, @ схема_таблицы + '.', '')
И i2.TABLE_SCHEMA = @table_schema
- СЕЙЧАС обрабатываем первичный ключ, заданный как параметр для основного пакета
SELECT @pk_separator = ',' - примите это по умолчанию, мы проверим ниже, если он другой
ЕСЛИ (@PK_condition IS NULL OR @PK_condition = '') AND @PK_COLUMN_NAME <> ''
НАЧИНАТЬ
ЕСЛИ CHARINDEX (';', @PK_COLUMN_NAME)> 0
ВЫБЕРИТЕ @pk_separator = ';'
ELSE IF CHARINDEX ('|', @PK_COLUMN_NAME)> 0
ВЫБЕРИТЕ @pk_separator = '|'
ELSE IF CHARINDEX ('-', @PK_COLUMN_NAME)> 0
ВЫБЕРИТЕ @pk_separator = '-'
SELECT @PK_condition = NULL - обязательно сделайте его NULL, если это было ''
ВСТАВИТЬ @stringsplit_table
ВЫБРАТЬ LTRIM (RTRIM (x.значение)), 'datetime' ОТ STRING_SPLIT (@PK_COLUMN_NAME, @pk_separator) x
ВЫБЕРИТЕ @PK_condition = ISNULL (@PK_condition + 'И', '') + QUOTENAME (x.col) + '=' + replace (QUOTENAME (x.col, '{'), '{', '{pk_')
ОТ @stringsplit_table x
SELECT @PK_COLUMN_NAME = NULL - обязательно сделайте его NULL, на случай, если это было ''
ВЫБЕРИТЕ @PK_COLUMN_NAME = ISNULL (@PK_COLUMN_NAME + ',', '') + QUOTENAME (x.col) + 'as pk_' + x.col
ОТ @stringsplit_table x
--print 'pkcolumns' + isnull (@PK_COLUMN_NAME, '')
обновить @stringsplit_table set col = 'pk_' + col
ВЫБЕРИТЕ @own_pk = 1
КОНЕЦ
ELSE IF (@PK_condition IS NULL OR @PK_condition = '') AND @PK_COLUMN_NAME = ''
НАЧИНАТЬ
RAISERROR ('В таблице нет столбца первичного ключа или идентификатора.Добавьте несколько столбцов в качестве третьего параметра при вызове этого SP, чтобы создать свой собственный временный PK., Также удалите [] из tablename ', 17,1)
КОНЕЦ
- ЕСЛИ в активной таблице нет первичных ключей или ключа идентификации, тогда используйте данные столбцы в качестве первичного ключа.
if isnull (@pkstring, '') = '' установить @pkstring = @PK_COLUMN_NAME
ЕСЛИ ISNULL (@pkstring, '') <> '' SELECT @fullquery = REPLACE (@fullquery, 'SELECT', 'SELECT' + @pkstring + ',')
--print @pkstring
- игнорировать поля для ЗАЯВЛЕНИЯ ОБНОВЛЕНИЯ (не игнорируется для оператора вставки, в операторе iserts мы игнорируем только столбцы идентификаторов и столбцы, предоставленные основной сохраненной процедурой)
- Поместите сюда все поля, которые, как вы знаете, не могут быть правильно преобразованы в значения nvarchar (), поэтому не должны быть скриптами для обновлений)
- для вставки мы возьмем эти поля с собой, хотя они будут отображаться некорректно !!!!!!!!!!!!!.ВЫБЕРИТЕ ignore_field = 'uniqueidXXXX' INTO #ignore
ОБЪЕДИНЕНИЕ ВСЕ ВЫБОР ignore_field = 'UPDATEMASKXXXX'
ОБЪЕДИНЕНИЕ ВСЕ ВЫБОР ignore_field = 'UIDXXXXX'
UNION ALL SELECT значение FROM string_split (@ ignore_field_input, @ pk_separator)
SELECT @getdate = REPLACE (REPLACE (REPLACE (REPLACE (CONVERT (NVARCHAR (30), GETDATE (), 121), '-', ''), '', ''), ':', ''), ' . ',' ')
ВЫБЕРИТЕ @tmp_table = 'Release_DATA__' + @getdate + '__' + REPLACE (@ table_name, @ table_schema + '.', '')
SET @sql = replace (@fullquery, 'from', 'INTO' + @tmp_table + 'from')
---- печать (@sql)
exec (@sql)
SELECT @sql = N'alter table '+ @tmp_table + N' добавить update_stmt1 nvarchar (max), update_stmt2 nvarchar (max), update_stmt3 nvarchar (max) '
EXEC (@sql)
- Подготовить список полей для обновления (для обновления берутся только столбцы из временной таблицы, если они также существуют в базовой таблице)
ВЫБРАТЬ @ update_list1 = ISNULL (@ update_list1 + ',', '') +
СЛУЧАЙ, КОГДА C1.COLUMN_NAME = 'ModifiedBy' THEN '[ModifiedBy] = left (right (replace (CONVERT (VARCHAR (19), [Modified], 121),' '' '-' '' ',' '' '' '' ') , 19) + '' '' - '' '' + право (SUSER_NAME (), 30), 50) '
КОГДА C1.COLUMN_NAME = 'Изменено' ТОГДА '[Изменено] = GETDATE ()'
ELSE QUOTENAME (C1.COLUMN_NAME) + '=' + QUOTENAME (C1.COLUMN_NAME, '{')
КОНЕЦ
ИЗ INFORMATION_SCHEMA.COLUMNS c1
внутреннее соединение INFORMATION_SCHEMA.COLUMNS c2
на c1.COLUMN_NAME = c2.COLUMN_NAME и c2.TABLE_NAME = REPLACE (@ table_name, @ table_schema + '.',' ') И c2.TABLE_SCHEMA = @table_schema
ГДЕ c1.TABLE_NAME = @tmp_table --REPLACE (@ table_name, @ table_schema + '.', '')
AND QUOTENAME (c1.COLUMN_NAME) NOT IN (SELECT QUOTENAME (ignore_field) FROM #ignore) - удалите здесь двоичное, изображение и т. Д. Значение
И COLUMNPROPERTY (идентификатор_объекта (c2.TABLE_SCHEMA + '.' + C2.TABLE_NAME), c2.COLUMN_NAME, 'IsIdentity') <> 1
И НЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE ку
ГДЕ 1 = 1
И ku.TABLE_NAME = c2.ТАБЛИЦА ИМЯ
И ku.TABLE_SCHEMA = c2.TABLE_SCHEMA
И ku.COLUMN_NAME = c2.COLUMN_NAME
И СВОЙСТВО ОБЪЕКТА (OBJECT_ID (ku.CONSTRAINT_SCHEMA + '.' + QUOTENAME (ku.CONSTRAINT_NAME)), 'IsPrimaryKey') = 1)
И НЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ @stringsplit_table x ГДЕ x.col = c2.COLUMN_NAME И @own_pk = 1)
- Подготовить список полей обновления (здесь мы берем только столбцы, которые начинаются с символа #, поскольку это наша очередь для выполнения обновления, поступающего из внутренней объединенной таблицы)
SELECT @ update_list2 = ISNULL (@ update_list2 + ',', '') + QUOTENAME (заменить (C1.COLUMN_NAME, '#', '')) + '=' + QUOTENAME (C1.COLUMN_NAME, '{')
ИЗ INFORMATION_SCHEMA.COLUMNS c1
ГДЕ c1.TABLE_NAME = @tmp_table - И c1.TABLE_SCHEMA = @table_schema
AND QUOTENAME (c1.COLUMN_NAME) NOT IN (SELECT QUOTENAME (ignore_field) FROM #ignore) - удалите здесь двоичное, изображение и т. Д. Значение
И c1.COLUMN_NAME как "#%"
- аналогично списку выбора, но занимает все поля
SELECT @select_list = ISNULL (@select_list + ',', '') + QUOTENAME (COLUMN_NAME)
ИЗ INFORMATION_SCHEMA.COLUMNS c
ГДЕ ИМЯ ТАБЛИЦЫ = ЗАМЕНИТЬ (@ имя_таблицы, @ схема_таблицы + '.',' ')
И TABLE_SCHEMA = @table_schema
AND COLUMNPROPERTY (object_id (TABLE_SCHEMA + '.' + TABLE_NAME), COLUMN_NAME, 'IsIdentity') <> 1 - столбцы идентификаторов автоматически заполняются MSSQL, не требуется при выполнении инструкции Insert
AND QUOTENAME (c.COLUMN_NAME) NOT IN (SELECT QUOTENAME (ignore_field) FROM #ignore) - удалите здесь двоичное, изображение и т. Д. Значение
ВЫБРАТЬ @PK_condition = REPLACE (@PK_condition, '[pk_', '[')
установите @ select_list = 'если не существует (выберите * из' + REPLACE (@ table_name, @ table_schema + '.', '') + 'where' + @PK_condition + ') INSERT INTO' + REPLACE (@ table_name, @ table_schema + ' .',' ') +' ('+ @select_list +') VALUES ('+ replace (replace (@select_list,' [',' {'),'] ','} ') +') '
ВЫБЕРИТЕ @sql = N'UPDATE '+ @tmp_table +' установить update_stmt1 = '' '+ @select_list +' '' '
если @ list_all_cols = 1 EXEC (@sql)
--print 'select ==========' + @select_list
--print 'update ==========' + @ update_list1
ВЫБЕРИТЕ @sql = N'UPDATE '+ @tmp_table + N'
установить update_stmt2 = CONVERT (NVARCHAR (MAX), '' UPDATE '+ @table_name +
N 'SET' + @ update_list1 + N '' '+' '' +
N 'ГДЕ' + @PK_condition + N '' ')'
EXEC (@sql)
--print @sql
ВЫБЕРИТЕ @sql = N'UPDATE '+ @tmp_table + N'
установить update_stmt3 = CONVERT (NVARCHAR (MAX), '' UPDATE '+ @table_name +
N 'SET' + @ update_list2 + N '' '+' '' +
N 'ГДЕ' + @PK_condition + N '' ')'
EXEC (@sql)
--print @sql
- ПЕРЕХОД ПО ВСЕМ столбцам базовых таблиц для INSERT INTO.... ЦЕННОСТИ
ОБЪЯВИТЬ c_columns КУРСОР FAST_FORWARD READ_ONLY ДЛЯ
ВЫБЕРИТЕ COLUMN_NAME, DATA_TYPE
ИЗ INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = (CASE WHEN @ list_all_cols = 0 THEN @tmp_table ELSE REPLACE (@ table_name, @ table_schema + '.', '') END)
И TABLE_SCHEMA = @table_schema
СОЮЗ - pned
ВЫБЕРИТЕ col, 'datetime' ИЗ @stringsplit_table
ОТКРЫТЬ c_columns
ВЫБРАТЬ ДАЛЕЕ ИЗ c_columns В @COLUMN_NAME, @COLUMN_NAME_DATA_TYPE
ПОКА @@ FETCH_STATUS = 0
НАЧИНАТЬ
ВЫБРАТЬ @sql =
СЛУЧАЙ, КОГДА @COLUMN_NAME_DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('float', 'real', 'money', 'smallmoney')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 126)), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', ''НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('уникальный идентификатор')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('текст', 'ntext')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('xxxx', 'yyyy')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('двоичный', 'varbinary')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('XML', 'xml')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 0)), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', ''НУЛЕВОЙ'')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('datetime', 'smalldatetime')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 121)), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', ''НУЛЕВОЙ'')) '
ЕЩЕ
N'UPDATE '+ @tmp_table + N' SET update_stmt1 = REPLACE (update_stmt1, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR ( MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОНЕЦ
---- ПЕЧАТЬ @sql
EXEC (@sql)
ВЫБРАТЬ ДАЛЕЕ ИЗ c_columns В @COLUMN_NAME, @COLUMN_NAME_DATA_TYPE
КОНЕЦ
ЗАКРЫТЬ c_columns
DEALLOCATE c_columns
--SELECT col FROM @stringsplit_table - это первичные ключи
- ПЕРЕХОД ПО ВСЕМ столбцам временных таблиц для значений обновления
ОБЪЯВИТЬ c_columns КУРСОР FAST_FORWARD READ_ONLY ДЛЯ
ВЫБЕРИТЕ COLUMN_NAME, DATA_TYPE
ОТ INFORMATION_SCHEMA.КОЛОННЫ
ГДЕ TABLE_NAME = @tmp_table - И TABLE_SCHEMA = @table_schema
СОЮЗ - pned
ВЫБЕРИТЕ col, 'datetime' ИЗ @stringsplit_table
ОТКРЫТЬ c_columns
ВЫБРАТЬ ДАЛЕЕ ИЗ c_columns В @COLUMN_NAME, @COLUMN_NAME_DATA_TYPE
ПОКА @@ FETCH_STATUS = 0
НАЧИНАТЬ
ВЫБРАТЬ @sql =
СЛУЧАЙ, КОГДА @COLUMN_NAME_DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), [' + @COLUMN_NAME + N '])),' '' '' '' ',' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('float', 'real', 'money', 'smallmoney')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 126)), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 126)), '' '' '' '' ',' '' '' '' '' '' ') +' '' '' '' ',' 'NULL' '))'
КОГДА @COLUMN_NAME_DATA_TYPE IN ('уникальный идентификатор')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), [' + @COLUMN_NAME + N '])),' '' '' '' ',' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('текст', 'ntext')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), [' + @COLUMN_NAME + N '])),' '' '' '' ',' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('xxxx', 'yyyy')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), [' + @COLUMN_NAME + N '])),' '' '' '' ',' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('двоичный', 'varbinary')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' ') +' '' '' '' ',' ' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), [' + @COLUMN_NAME + N '])),' '' '' '' ',' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОГДА @COLUMN_NAME_DATA_TYPE IN ('XML', 'xml')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 0)), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 0)), '' '' '' '' ',' '' '' '' '' '' ') +' '' '' '' ',' 'NULL' '))'
КОГДА @COLUMN_NAME_DATA_TYPE IN ('datetime', 'smalldatetime')
THEN N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 121)), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N'], 121)), '' '' '' '' ',' '' '' '' '' '' ') +' '' '' '' ',' 'NULL' '))'
ЕЩЕ
N'UPDATE '+ @tmp_table + N' SET update_stmt2 = REPLACE (update_stmt2, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR ( MAX), ['+ @COLUMN_NAME + N'])), '' '' '' '', '' '' '' '' '' '') + '' '' '' '', '' NULL '')), update_stmt3 = REPLACE (update_stmt3, '' {'+ @COLUMN_NAME + N'} '', ISNULL ('' '' '' '' + REPLACE (RTRIM (CONVERT (NVARCHAR (MAX), ['+ @COLUMN_NAME + N '])),' '' '' '' ',' '' '' '' '' '') + '' '' '' '', '' NULL '')) '
КОНЕЦ
EXEC (@sql)
---- печать @sql
ВЫБРАТЬ ДАЛЕЕ ИЗ c_columns В @COLUMN_NAME, @COLUMN_NAME_DATA_TYPE
КОНЕЦ
ЗАКРЫТЬ c_columns
DEALLOCATE c_columns
SET @sql = 'Выбрать * из' + @tmp_table + ';'
--exec (@sql)
ВЫБРАТЬ @sql = N '
ЕСЛИ OBJECT_ID ('' '+ @tmp_table + N' '', '' U '') НЕ ПУСТО
НАЧИНАТЬ
ВЫБЕРИТЕ '' USE '+ DB_NAME () +' '' как исполнитель
СОЮЗ ВСЕ
ВЫБЕРИТЕ "GO" в качестве исполнителя
СОЮЗ ВСЕ
ВЫБРАТЬ '' / * ПРОВЕРКА ПРЕДПИСАНИЯ * / '+ replace (@fullquery,' '' ',' '' '' ') +' '' как исполнитель
СОЮЗ ВСЕ
ВЫБЕРИТЕ update_stmt1 как исполнитель FROM '+ @tmp_table + N', где update_stmt1 не равно нулю
СОЮЗ ВСЕ
ВЫБЕРИТЕ update_stmt2 как исполнитель FROM '+ @tmp_table + N', где update_stmt2 не равно нулю
СОЮЗ ВСЕ
SELECT isnull (update_stmt3, '' добавьте больше столбцов в запрос, пожалуйста '') в качестве исполнителя FROM '+ @tmp_table + N', где update_stmt3 не равно null
СОЮЗ ВСЕ
ВЫБЕРИТЕ '' --EXEC usp_AddInstalledScript 5, 5, 1, 1, 1, '' '' '+ @tmp_table +'.sql '' '', 2 '' как исполнитель
СОЮЗ ВСЕ
ВЫБЕРИТЕ '' / * ПРОВЕРЬТЕ: * / '+ replace (@fullquery,' '' ',' '' '' ') +' '' как исполнитель
СОЮЗ ВСЕ
ВЫБЕРИТЕ '' - РАСПОЛОЖЕНИЕ СКРИПТА: F: \ CopyPaste \ ++ Distributionpoint ++ \ Release_Management \ '+ @tmp_table +' .sql '' в качестве исполнителя
КОНЕЦ'
exec (@sql)
НАБОР @sql = 'DROP TABLE' + @tmp_table + ';'
exec (@sql)
Как вставить данные из Excel в SQL Server
В этой статье вы узнаете, как легко выполнить одну из самых полезных задач по управлению данными: как вставить данные из Excel в SQL Server.
Фон
До того, как я основал SQL Spreads (надстройку Excel для импорта и обновления данных SQL Server из Excel), я много лет работал консультантом по бизнес-аналитике, используя инструменты бизнес-аналитики Microsoft, такие как SQL Server, SSIS, Reporting Services, Excel и др.
Я обнаружил, что, работая над разными проектами, я часто вспоминаю несколько важных вещей, которые я могу использовать снова и снова. Одна из тех вещей, которые я повторно использую почти в каждом проекте, — это возможность копировать и вставлять данные из Excel в таблицу в SQL Server.
Это действительно простой и удобный способ быстро импортировать данные в таблицу в SQL Server. Например, заполнение новой таблицы измерений, добавление некоторых тестовых данных или ввод любых других данных, которые вам нужны для быстрого ввода в таблицу в SQL Server. Вероятно, это самый простой способ вставки данных из Excel в SQL Server, но его часто упускают из виду.
В этой статье я расскажу об основах копирования и вставки данных из Excel в SQL Server за несколько простых шагов.Я также расскажу о нескольких особых случаях и методах, которые полезно знать.
Если вы много импортируете или обновляете данные из Excel в SQL Server, или если у вас есть пользователи, которые любят Excel, но не привыкли к инструментам базы данных, обратите внимание на надстройку SQL Spreads Excel, которую я с которыми работал последние несколько лет с тех пор, как оставил работу консультантом по бизнес-аналитике. Это значительно упрощает выполнение задач импорта из Excel в SQL Server!
Другие инструменты и методы
Для предприятий, которые полагаются на базы данных Microsoft SQL Server, необходимость вставки данных из Excel в SQL Server является постоянной задачей.Существует ряд инструментов и методов, доступных для выполнения этой задачи, каждый со своими преимуществами и разным уровнем сложности.
Я кратко рассмотрю несколько различных инструментов, а также их преимущества и варианты использования. Наиболее распространенные инструменты, доступные для импорта файла Excel в таблицу в SQL Server:
- Мастер импорта SQL Server — инструмент импорта на основе мастера в среде SQL Server Management Studio. Идеально подходит для одноразового импорта, когда у вас есть документ Excel, который нужно импортировать в таблицу в SQL Server.Плюсы включают гибкость и множество настроек для точной настройки импорта. Самый большой недостаток заключается в том, что вам нужно запускать дюжину диалогов Мастера с множеством настроек каждый раз, когда вам нужно импортировать данные. Дополнительную информацию о мастере импорта SQL Server можно найти здесь.
- SSIS — это нефтеналивной танкер для перемещения данных между разными источниками. Вы можете выполнить практически любую задачу, которая вам нравится, но вам нужно будет потратить много времени, чтобы начать работу, и еще больше времени уйдет на поддержку и изменение решения в будущем.К плюсам можно отнести хорошую универсальность и множество доступных функций; главный минус — это время, которое вам придется потратить на изучение инструмента. Более подробную информацию о SSIS можно найти здесь.
- Утилита BCP — инструмент на основе командной строки, который предлагает огромное количество настроек — если вы программист, это инструмент, который нужно использовать. Более подробную информацию об утилите BCP можно найти здесь.
Это отличные инструменты для перемещения данных, особенно если вам необходимо импортировать данные из Excel в SQL Server на ежедневной или еженедельной основе.Недостатком является то, что для настройки инструментов требуется несколько шагов, а для настройки потребуется некоторое время.
Преимущество описанной ниже техники «копирования и вставки» заключается в том, что она действительно быстрая и работает сразу после установки с использованием стандартных Excel и SQL Server Management Studio. Он также может обрабатывать таблицы с идентификационными столбцами и может управлять несколькими тысячами строк данных с разумным временем загрузки.
Как импортировать данные из Excel в SQL Server — пошаговые инструкции
- Откройте SQL Server Management Studio и подключитесь к своей базе данных SQL Server.
- Разверните папки Databases и Tables для таблицы, в которую вы хотите вставить данные из Excel.
- Щелкните таблицу правой кнопкой мыши и выберите четвертый вариант — Изменить первые 200 строк .
- Данные будут загружены, и вы увидите первые 200 строк данных в таблице.
- Переключитесь в Excel и выберите строки и столбцы для вставки из Excel в SQL Server.
Щелкните выделенные ячейки правой кнопкой мыши и выберите Копировать . - Вернитесь в SQL Server Management Studio, прокрутите вниз до последней строки внизу и найдите строку со звездочкой в крайнем левом столбце.
- Щелкните правой кнопкой мыши звездочку в заголовке столбца и выберите Вставить .
- Вы завершили импорт SQL Server, и ваши данные из Excel теперь находятся в таблице в SQL Server!
Помните : Всегда начинайте с копирования и вставки одной строки данных из Excel в SQL Server.Это необходимо для проверки того, что между вашими данными из Excel и таблицы SQL Server нет несоответствий (например, количество столбцов) и что ваши данные в Excel соответствуют типам данных в таблице SQL Server. См. Раздел «Советы и хитрости» ниже для получения более подробной информации.
ПРОФЕССИОНАЛЬНЫЙ СОВЕТ
Ищете действительно простой способ импортировать данные Excel в SQL Server?
Используйте надстройку SQL Spreads Excel для создания документов Excel, в которых вы (и другие пользователи) можете импортировать и обновлять данные в таблицах SQL Server непосредственно из Excel .
Просто вставьте данные, которые вы хотите импортировать, в документ SQL Spreads Excel и нажмите «Сохранить»:
Как импортировать данные из Excel в таблицу SQL Server со столбцом идентификаторов
Тот же метод можно использовать для копирования и вставки данных в таблицы, которые имеют столбец идентификатора с автоинкрементом (столбец идентификатора) .
Здесь следует иметь в виду, что при копировании данных из Excel в SQL Server необходимо также включать крайний левый пустой столбец в Excel.
Выполните следующие действия, чтобы скопировать и вставить данные из Excel в SQL Server, используя таблицу с автоматически увеличивающимся столбцом идентификатора:
- Откройте SQL Server Management Studio и подключитесь к своей базе данных SQL Server.
- Разверните папки Databases и Tables для таблицы, в которую вы хотите вставить данные Excel.
- Щелкните правой кнопкой мыши имя таблицы и выберите Изменить первые 200 строк , четвертый вариант сверху.
- Появится сетка с первыми 200 строками данных в таблице.
- Переключитесь в Excel и выберите строки и столбцы для копирования. Не включайте строку заголовка.
Теперь, также не забудьте включить дополнительный пустой крайний левый столбец в свой выбор .Затем щелкните выделенные ячейки правой кнопкой мыши и выберите Копировать .
- Вернитесь в SQL Server Management Studio и выберите вкладку с 200 строками из таблицы.
Перейдите к последней строке внизу и найдите строку со звездочкой в крайнем левом столбце . - Щелкните правой кнопкой мыши звездочку и выберите Вставить .
- Ваши данные из Excel теперь вставлены в вашу таблицу в SQL Server, и SQL Server автоматически создаст для вас значения в столбце идентификатора / ключа:
Копирование и вставка данных из Excel в SQL Server Views
Метод копирования и вставки также работает, когда вы импортируете из Excel в SQL Server в представление, а не в таблицу. Единственное требование — представление должно содержать данные только из одной таблицы.
В представлении в SQL Server, которое содержит данные из нескольких объединенных таблиц, вы не можете вставлять новые строки, но вы можете обновлять данные, если вы обновляете только столбцы, происходящие из той же базовой таблицы.
Советы при копировании данных из Excel на сервер SQL
Проверка данных — начните с одной строки данных
Если данные, которые вы копируете из документа Excel, не соответствуют типам данных столбцов в таблице SQL Server, вставка данных будет отменена, и вы получите предупреждающее сообщение.Это произойдет для каждой строки, которую вы вставляете из Excel в SQL Server. Если вы вставите 500 строк из Excel с неправильным количеством столбцов, вы получите одно предупреждение для каждой вставляемой строки.
Чтобы избежать этого, уловка состоит в том, чтобы начать копировать только одну строку данных и вставить ее в таблицу SQL Server. Если вы получили предупреждающее сообщение о неправильных типах данных, вы можете исправить несоответствие и повторять процедуру копирования и вставки, пока все столбцы Excel не поместятся в таблицу в SQL Server.Когда все столбцы совпадут, выберите оставшиеся строки и вставьте их все в таблицу SQL Server за один шаг.
Вставка значений NULL из Excel в таблицу SQL Server
Если у вас есть столбцы в таблице SQL Server, которые допускают значения NULL, и вы хотите вставить значение NULL в таблицу, просто введите текст NULL в ячейку в Excel, а затем скопируйте и вставьте данные из Excel в SQL Server. :
Значения NULL будут вставлены в таблицу в SQL Server:
Таблицы с вычисляемыми столбцами
Для таблиц SQL Server, содержащих вычисляемые столбцы, вы можете вставить данные из Excel в эту таблицу, просто оставив данные для вычисляемого столбца пустыми в Excel, а затем скопировав и вставив данные из Excel в таблицу SQL Server.
Как получить имена столбцов из таблицы в SQL Server в Excel
Когда вы подготавливаете данные в Excel для импорта в существующую таблицу SQL Server, полезно иметь заголовки столбцов и несколько строк образцов данных в качестве ссылки в Excel.
Существует метод, при котором вы можете скопировать существующие данные в SQL Server в Excel и включить имена столбцов таблицы в качестве имен заголовков.
Выполните следующие действия, чтобы также включить имена столбцов при копировании нескольких строк данных из таблицы SQL Server в Excel:
- В SQL Server Management Studio найдите свою базу данных и разверните папку Tables .
- Щелкните правой кнопкой мыши имя своей таблицы и выберите третий вариант — Выбрать первые 1000 строк .
- Выберите строки для копирования в Excel, удерживая нажатой кнопку CTRL и щелкая номера строк слева.
- Когда ваши строки выбраны, щелкните правой кнопкой мыши одну строку и выберите вариант Копировать с заголовками :
- Зайдите в Excel и вставьте данные в ячейку. Заголовки из таблицы в SQL Server теперь будут добавлены как первая строка:
Импорт из Excel в SQL Server на удаленном компьютере
При работе с базами данных SQL Server на удаленном компьютере, где вы подключаетесь к удаленному компьютеру с помощью подключения к удаленному рабочему столу, вы все равно можете использовать ту же технику копирования и вставки для перемещения данных из Excel локального компьютера в базу данных SQL Server на ваш удаленный компьютер.
Если вы не можете скопировать и вставить данные в свой SQL Server при подключении с помощью подключения к удаленному рабочему столу, сначала убедитесь, что копирование и вставка включены для подключения к удаленному рабочему столу:
- Откройте подключение к удаленному рабочему столу.
- Щелкните Показать параметры…
- Выберите вкладку Локальные ресурсы , а затем убедитесь, что свойство Буфер обмена отмечено:
Если вы по-прежнему не можете копировать и вставлять данные между Excel на локальном компьютере и SQL Server на удаленном сервере базы данных, узнайте у администратора сервера, включена ли функция копирования и вставки для подключения к удаленному рабочему столу на сервере.
Excel для производительности SQL Server
Копирование и вставка данных из Excel в SQL Server — действительно простой метод импорта данных из Excel в базу данных SQL Server. Один из недостатков заключается в том, что это не самый быстрый метод, если вам нужно вставить большие объемы данных, например несколько сотен тысяч строк данных или больше.
Чтобы получить ссылку на ограничения производительности, я провел несколько тестов на моем локальном компьютере i7 с 8 ГБ ОЗУ с Microsoft Excel и SQL Server, установленными на одном компьютере.
У меня были следующие результаты: копирование данных в Excel с 10 столбцами смешанных типов данных в SQL Server заняло около 2 секунд для 100 строк, около 30 секунд для 1000 строк и около 10 минут для 20 000 строк.
Итак, я бы сказал, что ограничение на использование функции копирования и вставки составляет от нескольких тысяч до нескольких десятков тысяч строк данных. Если вам нужно выполнить импорт из Excel в SQL Server с большим количеством данных, то более подходящим будет один из других методов, упомянутых ранее.
Требования и ограничения
Для копирования и вставки данных из Excel в SQL Server вам потребуются установленные Microsoft Excel и SQL Server Management Studio. Вы можете скачать бесплатную версию SQL Server Management studio здесь.
Копирование данных из Excel в SQL Server отлично подходит для нескольких тысяч строк данных с разумным временем загрузки.
Метод копирования и вставки подходит как для таблиц с бизнес-ключами, так и для таблиц с автоматически увеличивающимися ID-ключами.
Следует иметь в виду, что метод копирования и вставки предназначен только для вставки новых данных. Если вам нужно обновить существующие данные в таблице в SQL Server, вам нужно будет использовать либо внешний инструмент, такой как SQL Spreads, либо вставить данные во временную таблицу, а затем написать небольшой запрос SQL, который обновит вашу таблицу с помощью вставленные данные.
ПРИМЕЧАНИЕ
Есть ли у вас пользователи, которые любят Excel, но не привыкли к инструментам баз данных, и которым необходимо обновить данные SQL Server?
Используйте надстройку SQL Spreads Excel в режиме редактора для создания подключенных к SQL Server документов Excel, в которых пользователи могут импортировать и обновлять данные SQL Server из Excel.
Сводка — вставка данных из Excel в SQL Server
Если вам нужно быстро и легко импортировать данные из Excel в SQL Server, функция копирования и вставки — отличный вариант. Этот процесс прост и не требует каких-либо специальных знаний или инструментов и может использоваться в сценариях, содержащих до нескольких десятков тысяч строк данных.
Метод копирования и вставки также отлично подходит для таблиц с автоматически увеличивающимся ключом идентификации — просто не забудьте добавить дополнительный пустой столбец слева от столбцов данных, как описано выше.
Его также можно использовать при работе с Excel на локальном компьютере и SQL Server на удаленном компьютере с использованием подключения к удаленному рабочему столу.
Excel для SQL Server — краткий справочник:
- Сначала скопируйте данные из Excel, а затем вставьте их в таблицу SQL Server, используя пункт меню База данных > Таблица > Изменить верхние 200 строк .
- Всегда начинайте с копирования и вставки одной строки данных для проверки типов данных.
- Для таблиц SQL Server со столбцом идентификаторов добавьте дополнительный пустой крайний левый столбец перед копированием из Excel.
- Копирование и вставка из Excel в SQL Server может использоваться для вставки до нескольких десятков тысяч строк данных.
- Чтобы получить заголовки столбцов SQL Server в Excel, щелкните правой кнопкой мыши таблицу в SQL Server и выберите Копировать с заголовками .
- Не забывайте, что этот метод также отлично работает при подключении к удаленному рабочему столу!
Оператор INSERT SQL (Transact SQL)
Оператор INSERT используется для добавления строк в таблицу данных SQL Server.В этой статье мы исследуем, как использовать оператор INSERT. Мы обсуждаем передовой опыт, ограничения и подводим итоги на нескольких примерах.
Это вторая статья из серии статей. Первый — Введение в операторы изменения данных SQL Server.
Все примеры этого урока основаны на Microsoft SQL Server Management Studio и базе данных AdventureWorks2012. Правильно ли вы, , начинаете использовать SQL Server ? Если нет, сделайте это с помощью бесплатных инструментов, используя мое бесплатное руководство.
Прежде чем мы начнем
Хотя в этой статье в качестве примеров используется база данных Adventure Works, я решил создать примерную таблицу для использования в базе данных, чтобы лучше проиллюстрировать примеры. Здесь вы можете найти скрипт, который вам понадобится для запуска.
Базовая структура оператора INSERT SQL
Основная цель оператора INSERT — добавить строки в таблицу. Хотя оператор вставки вставляет данные из многих источников, таких как буквальные значения или исходные значения, основной формат остается тем же.
Оператор SQL INSERT состоит из трех компонентов. :
- Таблица, получающая новые строки.
- Столбцы для заполнения
- Исходные данные для новых строк.
Общий формат оператора Insert IS:
INSERT INTO tableName
(column1, column2,…)
VALUES (value1, value2,…)
Теперь мы сделаем несколько примеров вставок, поэтому, если вы еще не сделали этого, запустите сценарий, чтобы создать таблицу esqlSalesPerson.
SQL INSERT INTO — вставка одной строки
В этом примере мы вставляем одну строку в таблицу esqlSalesPerson. Вот его структура таблицы:
Предположим, мы хотим вставить в таблицу нового продавца. Команда для запуска:
INSERT INTO dbo.esqlSalesPerson
(FullName, SalesLastYear,
City, rowguid)
VALUES ('George Hitson', NULL,
'Midland', '794310D2-6293-4259-AC9A3-71D96 )
Обратите внимание, что мы не указали SalesPersonID в списке столбцов.Это столбец идентификаторов, который заполняется автоматически.
Столбцы можно переключать; они не должны быть в порядке. Также обратите внимание, что указаны не все столбцы:
INSERT INTO dbo.esqlSalesPerson
(City, FullName,
rowguid)
VALUES ('Traverse City', 'Donald Sax',
'F6E26EFD-5838-40F8-ABB3-D73487D29328 )
Создает следующую строку:
Обратите внимание, что, поскольку SalesLastYear не был указан, он имеет значение NULL:
Заключите значения столбцов в круглые скобки.Это представляет собой одну строку данных. Чтобы вставить более одной строки, просто включите другой набор значений столбца. Просто не забудьте разделить каждый набор запятой, как показано ниже:
INSERT INTO dbo.esqlSalesPerson (City, FullName, rowguid)
VALUES ( 'Bay City', 'Ralph Gitter',
'DED7DB59-7149-47DD- 8D8F-D5FCFFF11124 '),
(' Alpena ',' Mike Orange ',
' 94600A1E-DD83-4ACE-9D59-8CD727A2C83E ')
Прежде чем продолжить более сложный пример сделайте шаг назад и рассмотрите поведение оператора SQL INSERT и некоторые передовые методы.
Использование вставки: рекомендации и передовые методы
Рекомендации по типу данных (заполнение)
Имейте в виду, что при вставке данных в столбцы с типом данных CHAR, VARCHAR или VARBINARY заполнение или усечение данных зависит от SET ANSI_PADDING параметр.
Вставка значения «Kris» в поле, определенное как CHAR (10), приводит к значению, заполненному шестью дополнительными пробелами. Введено значение «Kris». Правило заполнения может сбивать с толку при использовании INSERT INTO, поэтому, пожалуйста, ознакомьтесь с этой статьей, чтобы узнать подробности.
Обработка ошибок
Ошибки можно обрабатывать при выполнении оператора INSERT INTO с помощью конструкции TRY… CATCH.
Есть несколько распространенных причин, по которым оператор INSERT может не работать. Вот некоторые из наиболее распространенных:
- Нарушение уникального ключа — вы пытаетесь вставить запись в таблицу, что приводит к дублированию значения ключа.
- Нарушение первичного ключа — вы пытаетесь вставить запись в таблицу, в которой уже есть строка с таким же первичным ключом.
- Нарушение внешнего ключа — вы пытаетесь вставить строку в «дочернюю» таблицу, но «родительская» не существует.
- Преобразование типа данных — Вы пытаетесь вставить строку, в которой одно из значений не может быть правильно преобразовано в соответствующий тип данных столбца.
В этих случаях выполнение оператора INSERT останавливается, а INSERT генерирует ошибку, и в таблицу не вставляются строки.
Имейте в виду, что вы можете изменить это поведение «все или ничего» для арифметических ошибок.Рассмотрим деление на нулевую ошибку.
INSERT INTO myNumbers (x, y)
VALUES (10/0, 5),
(10/5, 2),
(10/2, 5)
Этот расчет генерирует ошибку, если для SET ARITHABORT установлено значение НА. В этом случае вставка останавливается, строки не вставляются и выдается ошибка.
Однако, если для SET ARITHABORT установлено значение OFF, а для ANSI_WARNINGS установлено значение OFF, то тот же оператор будет успешно завершен.
Когда он установлен на ВЫКЛ, ошибка устанавливает результат в ПУСТО (NULL).
Например,
ВЫКЛЮЧИТЬ ARITHABORT
ВЫКЛЮЧИТЬ ANSI_WARNINGS
ВСТАВИТЬ В myNumbers (x, y)
ЗНАЧЕНИЯ (10/0, 5),
(10/5, 2),
(10/2, 5)
добавляет три строки со значениями
При добавлении строк в таблицы важно понимать, что есть некоторые столбцы, требующие особой обработки.
INSERT SELECT и уникальные идентификаторы
При добавлении данных в столбец, объявленный с типом uniqueidentifier, используйте функцию NEWID (), чтобы сгенерировать глобально уникальное значение.
В качестве примера
INSERT INTO dbo.esqlSalesPerson
(City, FullName, rowguid)
VALUES ('Traverse City', 'Donald Sax', NEWID ())
Вставляет новую строку в esqlSalesPerson. Если вы снова запустите команду, будет добавлена еще одна строка, но значение rowguid будет другим.
NEWID () генерирует новое значение при каждом вызове.
Свойство столбца идентификатора
Новое значение создается для столбца всякий раз, когда строка вставляется в таблицу со свойством столбца идентификатора.По этой причине, поскольку esqlSalesPerson.SalesPersonID является столбцом идентификаторов, мы не указываем его в нашем операторе INSERT. Значение идентификатора увеличивается каждый раз при добавлении строки.
Если вы попытаетесь вставить строку, используя собственное значение, вы получите ошибку.
Оператор INSERT
INSERT INTO dbo.esqlSalesPerson
(SalesPersonID, City, FullName, rowguid)
VALUES (9999, 'Traverse City', 'Donald Sax', NEWID ())
Генерирует ошибку
Can явное значение для столбца идентификаторов в таблице 'esqlSalesPerson', когда для IDENTITY_INSERT установлено значение OFF.
Чтобы обойти это, вы можете УСТАНОВИТЬ IDENTITY_INSERT для
УСТАНОВИТЬ IDENTITY_INSERT esqlSalesPerson ON;
INSERT INTO dbo.esqlSalesPerson
(SalesPersonID, City, FullName, rowguid)
VALUES (9999, 'Traverse City', 'Donald Sax', NEWID ())
Выполняется без ошибок.
Значения по умолчанию и прочее
При вставке строк, все не указанные столбцы получают значение от СУБД; в противном случае строка не загружается.
СУБД автоматически предоставляет значения для столбцов, если:
- столбец является столбцом IDENTITY (см. Выше)
- задано значение по умолчанию и не указано другое значение.
- столбец допускает значение NULL. Здесь СУБД устанавливает для столбца значение NULL.
- Колонна коммутируемая. Здесь используется расчет.
Если значение не указано в инструкции и механизм не может предоставить значение, строка не может быть вставлена. Обычно это происходит, когда значение отсутствует, а столбец НЕ ПУСТОЙ.
Вставка данных из других таблиц
Вы также можете использовать оператор INSERT INTO SELECT для вставки одной или нескольких строк из одной таблицы в другую.Результаты SELECT подаются во INSERT INTO.
Общая форма:
INSERT INTO targetTable (column1, column2,…)
SELECT (column1, column2,…)
FROM sourceTable
Предположим, менеджер по продажам Adventure Works хочет создать таблицу SalesPerson и включать только продажи люди, чьи прошлогодние продажи превысили 1 000 000 долларов.
Вставка с внутренним соединением
Чтобы заполнить эту таблицу, вы можете выполнить следующий INSERT SELECT:
INSERT INTO esqlSalesPerson
(FullName, SalesLastYear, rowguid)
SELECT P.FirstName + '' + P.LastName, S.SalesLastYear, NEWID ()
FROM Sales.SalesPerson S
INNER JOIN Person.Person P
ON P.BusinessEntityID = S.BusinessEntityID
ГДЕ S.SalesLastYear> 1000000
Для это для правильной работы столбцы, возвращаемые оператором SELECT, должны быть в том же порядке, что и указанный в списке столбцов INSERT. В этом примере обратите внимание, что rowguid является обязательным полем. Чтобы заполнить это значение, мы используем функцию NEWID ().
Вы также можете использовать обычное табличное выражение для определения строк для вставки.
Insert с CTE
Вы также можете написать пример как CTE (общее табличное выражение):
WITH topSalesPerson (FullName, SalesLastYear, rowguid)
AS (
SELECT P.FirstName + '' + P.LastName, S .SalesLastYear, NEWID ()
ОТ Sales.SalesPerson S
INNER JOIN Person.Person P
ON P.BusinessEntityID = S.BusinessEntityID
ГДЕ S.SalesLastYear> 1000000)
INSERT INTO esqlSalesPerson
(Full) FullName, SalesLastYear, rowguid
ОТ topSalesPerson
Хотя здесь больше набора текста, мне нравится метод CTE.Я думаю, это упрощает чтение инструкции INSERT.
Помните, что при использовании оператора SELECT для вставки данных в другую таблицу рекомендуется сначала просто запустить оператор SELECT, чтобы убедиться, что вы выбираете правильные строки. Кроме того, всегда разрабатывайте и тестируйте свой код! Я настоятельно рекомендую использовать копию вашей базы данных для разработки.
Подробнее: Оператор SQL UPDATE >>
Sql Insert Into Select | Bulk Rows Insert
Оператор SQL INSERT INTO SELECT копирует данные (все или выбранные пользователем) из одной таблицы базы данных и вставляет их в существующую таблицу базы данных.
По умолчанию оператор SQL INSERT INTO копирует только одну запись за раз . Но мы можем использовать оператор SQL INSERT INTO SELECT для копирования одной записи или нескольких записей одновременно .
Примечание. Таким образом, если вы копируете данные из исходной таблицы, это действие не повлияет на любые существующие записи в целевой таблице.
Вы также можете выполнить поиск по этим темам, используя sql insert into select, insert into select sql server, insert into select from, sql server insert into select from table, sql query insert into select, sql insert into select from the same table, multiple insert sql , множественная вставка в sql, вставка в синтаксис, вставка из выбора, вставка в куда, вставка в таблицу, вставка в значения .
Синтаксис SQL INSERT INTO SELECT
Приведенный ниже синтаксис используется для выбора всех столбцов и записей из одной таблицы в другую существующую таблицу.
ВСТАВИТЬ INTO имя_таблицы2
ВЫБРАТЬ * ИЗ имя_таблицы1;
Приведенный ниже синтаксис используется для выбора определенных столбцов из одной таблицы в другую существующую таблицу.
ВСТАВИТЬ INTO имя_таблицы2
(имя_столбца_список)
ВЫБРАТЬ column_name_list (s)
FROM table_name1;
Примечание. Приведенный выше синтаксис является очень простым.Весь оператор sql может содержать
SQL WHERE, SQL ORDER BY и SQL GROUP BY , а также таблица JOINS и псевдонимы .
Образец таблицы базы данных — Книга1
BookId | BookName | Описание |
---|---|---|
101 | Sql Полная ссылка | Он описывает, как записывать и выполнять оператор SQL в базе данных. |
102 | Sql-команды | Показывает список команд SQL. |
103 | Pl Sql Быстрое программирование | Как писать и выполнять программирование SQL с помощью pl sql. |
Образец таблицы базы данных — Книга2
BookId | Имя автора | Имя домена | ЗаказатьЦена |
---|---|---|---|
101 | Суреш Бабу | База данных | 250.5 |
102 | Шива Кумар | Программирование | 120 |
Пример таблицы базы данных — Books3
BId | B Название | BP Цена | Имя автора | B, домен |
---|---|---|---|---|
1 | Краткий справочник по MySQL 5.0 | 140 | Суреш Бабу | База данных |
2 | База данных Microsoft SQL Server | 100 | Харис Картик | База данных |
3 | Руководство по программированию Pl / Sql | 50 | Шива Кумар | Программирование |
SQL INSERT INTO SELECT, пример
Следующий оператор SQL SELECT скопирует только несколько столбцов из таблицы «Book1» в таблицу «Book3»
ВСТАВИТЬ В Книгу 3 (BId, BName)
ВЫБЕРИТЕ BookID, BookName FROM Book1;
Приведенный выше оператор sql скопирует все столбцы данных «BookID» и «BookName» из таблицы «Book1» и вставит их в столбцы «BID» и «BName» из таблицы «Book2».
После выполнения вышеуказанного оператора таблица «Book3» будет выглядеть так:
BId | B Название | BP Цена | Имя автора | B, домен |
---|---|---|---|---|
1 | Краткий справочник по MySQL 5.0 | 140 | Суреш Бабу | База данных |
2 | База данных Microsoft SQL Server | 100 | Харис Картик | База данных |
3 | Руководство по программированию Pl / Sql | 50 | Шива Кумар | Программирование |
101 | Sql Полная ссылка | |||
102 | Sql-команды | |||
103 | Pl Sql Быстрое программирование |
Следующий оператор SQL SELECT копирует только домен «Программирование» из «Book1» в «Book3»
ВСТАВИТЬ В Book3 (BPrice, AuthorName, BDomain)
ВЫБЕРИТЕ BookPrice, AuthorName, DomainName FROM Book2
ГДЕ DomainName = «Программирование»;
Приведенный выше оператор sql скопирует все столбцы данных «BookPrice», «AuthorName» и «BDomain» из таблицы «Book2» и вставит их в
Столбцы «BPrice», «AuthorName» и «BDomain» из таблицы «Book3».
После выполнения вышеуказанного оператора таблица «Book3» будет выглядеть так:
BId | B Название | BP Цена | Имя автора | B, домен |
---|---|---|---|---|
1 | Краткий справочник по MySQL 5.0 | 140 | Суреш Бабу | База данных |
2 | База данных Microsoft SQL Server | 100 | Харис Картик | База данных |
3 | Руководство по программированию Pl / Sql | 50 | Шива Кумар | Программирование |
101 | Sql Полная ссылка | |||
102 | Sql-команды | |||
103 | Pl Sql Быстрое программирование | |||
120 | Шива Кумар | Программирование |
Примечание: В невыбранных столбцах будет значение NULL.