Имя: Пароль:
IT
Админ
Как в таблицу MS SQL добавить строки с ключевым полем без автоинкремента?
0 MaxS
 
31.05.16
16:16
Как побороть такую ошибку при попытке добавить строки в таблицу MS SQL? Интересует вариант не требующий внесения изменений в БД.
Поле MYNO - это первичный ключ.

Не удалось вставить значение NULL в столбец "MYNO", таблицы "master.dbo.MYTAB"; в столбце запрещены значения NULL. Ошибка в UPDATE.
Выполнение данной инструкции было прервано.
1 Господин ПЖ
 
31.05.16
16:18
>в столбце запрещены значения NULL

что не ясного
2 Господин ПЖ
 
31.05.16
16:18
+

Поле MYNO - это первичный ключ.
3 MaxS
 
31.05.16
16:20
(1) Это ясно, но не хочется заниматься вычислением уникального значения, т.к. добавление происходит только тех записей, которых нет во временной таблице и всё это делается одним обращением к серверу.
Хочется чтобы оно само заполнялось ))
4 trad
 
31.05.16
16:26
тип какой?
5 trad
 
31.05.16
16:28
и полуОфф
ты уверен что нужно напрямую трогать таблицы из master?
6 ДенисЧ
 
31.05.16
16:28
set identityinsert off и вставлять свои поля
7 trad
 
31.05.16
16:29
(6) поле итак "без автоинкремента"
8 MaxS
 
31.05.16
16:30
(4) decimal(10,0) not null
(5) да я и не трогал мастер, это QA такое выдал в запросе обращение к dbo.MYTAB.
9 trad
 
31.05.16
16:31
(8) "это QA такое выдал"
интересное кино
10 trad
 
31.05.16
16:34
insert into mytab
select
  max(myno)+1,
  /*значение других полей*/
from mytab
11 MaxS
 
31.05.16
16:38
(9) sql server management studio  если быт точнее ))
(10) Это для добавления одной записи? А как сотню - другую?
12 MaxS
 
31.05.16
16:41
За основу был взят этот запрос из одной конфигурации из открытых источников. ;)
У меня почти такое же формируется программно для других таблиц и полей.

SELECT
    TempTable1.Deletion AS Deletion,
    TempTable1.CONO AS CONO,
    TempTable1.NAME AS NAME
INTO #TempTable1
FROM (

    SELECT
        0 AS Deletion,
        '00069    ' AS CONO,
        'Жена Калинин Федор Якубович' AS NAME

    UNION ALL

    SELECT
        0 AS Deletion,
        '00070    ' AS CONO,
        'Жена Маков Денис Георгиевич' AS NAME

    UNION ALL


) AS TempTable1

;

MERGE INTO CU_COMP AS CU_COMP
    USING (
        SELECT
            TempTable1.CONO AS CONO,
            TempTable1.NAME AS NAME
        FROM #TempTable1 AS TempTable1
        WHERE TempTable1.Deletion = 0
    ) AS TempTable1
    ON TempTable1.NAME = CU_COMP.NAME
    WHEN MATCHED THEN
        UPDATE SET
            CU_COMP.CONO = TempTable1.CONO
    WHEN NOT MATCHED THEN
        INSERT (CONO, NAME)
            VALUES (
                TempTable1.CONO,
                TempTable1.NAME
            )

;

DELETE CU_COMP
FROM CU_COMP AS CU_COMP, #TempTable1 AS TempTable1
WHERE CU_COMP.NAME = TempTable1.NAME
    AND TempTable1.Deletion = 1

;

DROP TABLE #TempTable1
13 MaxS
 
31.05.16
16:43
(12)  последний UNION ALL  там лишний, запрос руками сократил.
14 trad
 
31.05.16
16:44
(11) "Это для добавления одной записи? А как сотню - другую?"
сценарий может сильно зависеть от источника этой сотни записей
15 MaxS
 
31.05.16
16:49
(14) источник - переменная с типом таблица значений в модуле 1С.
Всю её загружаю во временную таблицу в MS SQL. Уже переделал запрос выше, получаю в итоге временную таблицу с записями, которых нет в таблице MYTAB. с двумя колонками MYNO, где все значения NULL и допустим MYNAME с наименованием товара.
16 trad
 
31.05.16
17:11
временную таблицу так же юнионом собираешь?
17 MaxS
 
31.05.16
17:21
(16) Уже нет.
SELECT *
INTO #TempTable2
FROM #TempTable1 ...
WHERE ...
18 MaxS
 
31.05.16
17:25
Задача пока свелась к необходимости перенумеровать колонку временной таблицы. Или получить из этой таблицы результат запроса с последовательно нумерованной колонкой.
19 MaxS
 
31.05.16
17:50
(16) Вернее первую таблицу через UNION ALL, там нет колонки MYNO потом сравниваю с имеющимися данными и получаю временную таблицу с записями, которых нет в ИБ.
То самое поле MYNO появляется в #TempTable2 из таблицы с рабочими данными.
20 MaxS
 
31.05.16
21:28
Странно, что никто не ответил. Как оказалось, это азы.
Как всегда сам спросил сам и ответил ))

SELECT     MYNO , MYNAME , ROW_NUMBER() over (order by MYNO ) + 400 as NN
INTO #TempTable2
FROM ...

Получаем колонку NN с числами 401, 402 и т.п. Где 400 - максимальный существующий номер.
Если кроме нас никто не добавляет данные в эту таблицу, то можно спокойно добавлять с данными из колонки NN.
21 DrZombi
 
гуру
31.05.16
21:48
(11) >>> Это для добавления одной записи? А как сотню - другую?

Смешно. Вы узко мыслите. На Скуле нет одной записи при таком запросе... И да тригер попробуй использовать, при создании новой записи :)

(20) Спасибо, отстой...
22 Fram
 
31.05.16
22:45
(21) ТС просил без изменений структуры БД.. так что на твой пост можно ответить твоими же словами :)
23 MaxS
 
01.06.16
05:34
(21) Раз сказали А, говорите и Б. Примерчик бы увидеть. Создать несколько записей во временной таблице и добавить их в таблицу в БД.
24 MaxS
 
01.06.16
06:58
Нашлось красивее решение - создать пустую временную таблицу с автоинкрементным полем и при добавлении туда строк с колонкой MYNAME, поле MYNO будет автоматически заполняться уникальными значениями.

CREATE TABLE #TempTable2
(
MYNO INT not null identity(400,1) PRIMARY KEY ,
MYNAME    nvarchar(254) not null
)

Пока непонятно как в одной конструкции TSQL вычислить максимальное значение MYNO+1 и передать в текст создания временной таблицы
25 Fram
 
01.06.16
07:17
(24) Ну либо через переменную, либо прямо туда вместо 400 селект засунь. сам не пробовал, но должно получиться
26 trad
 
01.06.16
09:16
(24) да, неплохо
27 trad
 
01.06.16
09:18
только я не очень понял зачем весь этот огород со временными таблицами.
я бы перебирая ТЗ закинул записи в поштучно
28 MaxS
 
01.06.16
09:34
(27) Допустим в SQL сотни тысяч строк, из 1С поступает сотня строк. Нужно найти те строки ТЗ из 1С, которые новые. Поэтому пришлось запихнуть ТЗ из 1С во временную таблицу, сравнить с БД и подготовить другую таблицу для записи в БД.
А дёргать по одной строке - мне такой вариант не нравится. Лучше долго запрягать и быстро долететь.
29 trad
 
01.06.16
09:57
(28) как я понимаю сейчас такая схема:
1. один запрос со 100 юнионами для вставки в темп1
2. соединение темп1 с целевой таблицей и получение темп2
3. вставка темп2 в целевую

очень сильно сомневаюсь что это будет эффективнее, чем
100 раз по:
if exists(select myno from mytab where ...)
begin
insert into mytab
select max(myno)+1, ...
end

но как говорится: хозяин - барин
30 MaxS
 
01.06.16
10:30
(29) вариант с временными таблицами отлаживать проще, как мне показалось. ;) Видна вся таблица перед помещением в целевую.
31 Fram
 
01.06.16
17:24
кстати, насчет 1с -> sql.. а файловый доступ к одной папке у обоих серверов есть? если есть, тогда bulk insert будет более эффективен.
32 MaxS
 
01.06.16
18:24
(31) Может быть на будущее пригодится. Но решение готовится для нескольких клиентов. В первую очередь нужен не быдлокод и работающее решение. Потом если потребуется будет оптимизация.
А нельзя SQL серверу через соединение отдать файл, чтобы он положил его у себя во временную папку и вернул бы путь к файлу, остальное дело техники. ;)
33 Fram
 
01.06.16
19:44
(32) напиши новый провайдер подключения к БД, который позволит провернуть такой трюк :)
как вариант ftp можно поднять рядом с sql, но вряд ли ты так будешь заморачиваться. хотя когда речь зайдет за сотни тысяч записей тогда может и захочешь заморочиться