Нужно, чтобы оператор SQL фокусировался на комбинации таблиц, но записи всегда имели уникальный идентификатор - PullRequest
5 голосов
/ 08 июня 2010

Мне нужен код SQL для решения проблемы комбинации таблиц, описанной ниже:

Таблица старых данных: таблица старых

    name     version    status    lastupdate      ID
    A        0.1        on        6/8/2010        1
    B        0.1        on        6/8/2010        2
    C        0.1        on        6/8/2010        3
    D        0.1        on        6/8/2010        4
    E        0.1        on        6/8/2010        5
    F        0.1        on        6/8/2010        6
    G        0.1        on        6/8/2010        7

Таблица новых данных: таблица новых

    name     version    status    lastupdate     ID         
    A        0.1        on        6/18/2010                
                                                           #B entry deleted
    C        0.3        on        6/18/2010                #version_updated
    C1       0.1        on        6/18/2010                #new_added
    D        0.1        on        6/18/2010                
    E        0.1        off       6/18/2010                #status_updated
    F        0.1        on        6/18/2010                
    G        0.1        on        6/18/2010                
    H        0.1        on        6/18/2010                #new_added
    H1       0.1        on        6/18/2010                #new_added

разница новых данных и старой даты:

B запись удалена

Обновлена ​​версия записи C

Обновлен статус записи E

C1 / H / H1 добавлена ​​новая запись

То, что я хочу, - это всегда сохранять отношение отображения ID-имени в старой таблице данных, независимо от того, как данные изменились позже, a.k.a имя всегда имеет уникальный идентификационный номер, связанный с ним.

Если запись обновлена, обновите данные, если запись добавлена ​​заново, вставьте в таблицу, затем присвойте новый уникальный идентификатор. Если запись была удалена, удалите запись и не используйте этот идентификатор позже.

Тем не менее, я могу использовать SQL только с простым оператором выбора или обновления, тогда мне может быть слишком сложно писать такой код, тогда я надеюсь, что кто-то с опытом может дать указания, никаких подробностей о различных вариантах SQL не требуется SQL-код в качестве образца достаточно.

Заранее спасибо!

RGS

KC

======== Я перечислил мой проект sql здесь, но не уверен, что он работает, кто-то с опытом, пожалуйста, прокомментируйте, спасибо!

1.дублируйте старую таблицу как tmp для обновлений магазина

создать таблицу tmp как выберите * из старого

2. обновить в tmp, где "имя" одинаково в старой и новой таблицах

обновление tmp где имя в (выберите имя из новых)

3.внесите другое имя (старое или новое) в tmp и назначьте новый идентификатор

вставить в tmp (имя версии, статус lastupdate ID) установите idvar = max (выберите max (id) из tmp) + 1 выбрать из (выберите new.name new.version new.status new.lastupdate new.ID из старого, нового где old.name <> new.name)

4. удалить удаленные записи из таблицы tmp (например, B)

удалить из tmp где (выберите ???)

Ответы [ 7 ]

1 голос
/ 18 июня 2010

Это работает в Informix и дает именно тот дисплей, который вам необходим. Можно подумать, что такой же или похожий должен работать в MySQL. Хитрость заключается в том, чтобы получить объединение всех имен во временную таблицу и включить в нее левое соединение, чтобы можно было сравнить значения двух других.

SELECT DISTINCT name FROM old
UNION
SELECT DISTINCT name FROM new
INTO TEMP _tmp;

SELECT 
  CASE WHEN b.name IS NULL THEN ''
       ELSE aa.name
       END AS name, 
  CASE WHEN b.version IS NULL THEN ''
       WHEN a.version = b.version THEN a.version 
       ELSE b.version
       END AS version,
  CASE WHEN a.status = b.status THEN a.status 
       WHEN b.status IS NULL THEN ''
       ELSE b.status
       END AS status,
  CASE WHEN a.lastupdate = b.lastupdate THEN a.lastupdate 
       WHEN b.lastupdate IS NULL THEN null
       ELSE b.lastupdate
       END AS lastupdate,
  CASE WHEN a.name IS NULL THEN '#new_added'
       WHEN b.name IS NULL THEN '#' || aa.name || ' entry deleted'
       WHEN a.version  b.version THEN '#version_updated'
       WHEN a.status  b.status THEN '#status_updated'
       ELSE ''
  END AS change
  FROM _tmp aa
  LEFT JOIN old a
         ON a.name = aa.name
  LEFT JOIN new b
         ON b.name = aa.name;
1 голос
/ 16 июня 2010

Примечание - если вас беспокоит производительность, вы можете пропустить весь этот ответ :-)

Если вы можете перепроектировать две таблицы - одну с данными, а другую с именем - идентификатор связи.Что-то вроде

table_original

name     version    status    lastupdate
A        0.1        on        6/8/2010
B        0.1        on        6/8/2010
C        0.1        on        6/8/2010
D        0.1        on        6/8/2010
E        0.1        on        6/8/2010
F        0.1        on        6/8/2010
G        0.1        on        6/8/2010

и name_id

name     ID 
A        1 
B        2 
C        3 
D        4 
E        5 
F        6 
G        7

Когда вы получаете table_new с новым набором данных

  1. TRUNCATEtable_original
  2. INSERT INTO name_id (имена из table_new не в name_id)
  3. копировать table_new в table_original

Примечание: я думаю, что здесь есть некоторая двусмысленность относительно удаления

Если запись была удалена, удалите запись и не используйте этот идентификатор позже.

Если имя A будет удалено и снова появится в более позднем набореобновлений вы хотите.повторно использовать исходный идентификатор, помеченный как A, или b.создать новый идентификатор?

Если это б.вам нужен столбец удален?в name_id и последнем шаге

4.установить Удалено?= Y, где имя, отсутствующее в table_original

и 2. исключило бы удаление?= Y records.

Вы также можете сделать то же самое без таблицы name_id, основываясь на логике, что единственное, что вам нужно из table_old - это ссылки name - ID.Все остальное, что вам нужно, находится в table_new,

1 голос
/ 09 июня 2010

Вы никогда не упоминали, какую СУБД вы используете, но если вы используете SQL Server, один действительно хороший - это оператор SQL MERGE.См .: http://www.mssqltips.com/tip.asp?tip=1704

Оператор MERGE в основном работает как отдельный оператор вставки, обновления и удаления в одном и том же операторе.Вы указываете набор записей «Источник» и «Целевую» таблицу, а также соединение между ними.Затем вы указываете тип модификации данных, который должен выполняться, когда записи между этими двумя данными совпадают или не совпадают.MERGE очень полезен, особенно когда речь идет о загрузке таблиц хранилища данных, которые могут быть очень большими и требовать определенных действий, когда строки присутствуют или отсутствуют.

Пример:

MERGE Products AS TARGET
USING UpdatedProducts AS SOURCE 
ON (TARGET.ProductID = SOURCE.ProductID) 
--When records are matched, update 
--the records if there is any change
WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName 
OR TARGET.Rate <> SOURCE.Rate THEN 
UPDATE SET TARGET.ProductName = SOURCE.ProductName, 
TARGET.Rate = SOURCE.Rate 
--When no records are matched, insert
--the incoming records from source
--table to target table
WHEN NOT MATCHED BY TARGET THEN 
INSERT (ProductID, ProductName, Rate) 
VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate)
--When there is a row that exists in target table and
--same record does not exist in source table
--then delete this record from target table
WHEN NOT MATCHED BY SOURCE THEN 
DELETE
--$action specifies a column of type nvarchar(10) 
--in the OUTPUT clause that returns one of three 
--values for each row: 'INSERT', 'UPDATE', or 'DELETE', 
--according to the action that was performed on that row
OUTPUT $action, 
DELETED.ProductID AS TargetProductID, 
DELETED.ProductName AS TargetProductName, 
DELETED.Rate AS TargetRate, 
INSERTED.ProductID AS SourceProductID, 
INSERTED.ProductName AS SourceProductName, 
INSERTED.Rate AS SourceRate; 
SELECT @@ROWCOUNT;
GO
1 голос
/ 08 июня 2010

Позвольте мне начать с конца:

В # 4 вы удалили бы все строки в tmp; то, что вы хотели сказать, есть WHERE tmp.name NOT IN (SELECT name FROM new); аналогично # 3 - неправильный синтаксис, но в таком случае он попытается вставить все строки.

Что касается # 2, почему бы не использовать с автоматическим приращением на ID?

Что касается # 1, если ваша таблица tmp такая же, как новая, запросы № 2- # 4 не имеют смысла, если вы не измените (обновите, вставите, удалите) new таблицу каким-либо образом.

Но (!), Если вы обновите таблицу new, и она имеет поле автоинкремента на ID и если вы правильно обновляете таблицу (используя ID) из приложение, то вся ваша процедура ненужна (!).

Итак, важно то, что вы не должны проектировать систему так, как описано выше.

Чтобы получить концепцию обновления данных в базе данных со стороны приложения, взгляните на примеры здесь (php / mysql).

Кроме того, чтобы получить правильный синтаксис в ваших запросах, выполните базовую версию команд SET, INSERT, DELETE и SELECT (никак не обойтись).

0 голосов
/ 25 июня 2010

Почему вы не используете UUID для этого? Сгенерируйте его один раз для плагина и включите / сохраните в плагин, а не в БД. Теперь, когда вы упомянули Python, вот как его сгенерировать:

import uuid
UID = str(uuid.uuid4()) # this will yield new UUID string

Конечно, это не гарантирует глобальную уникальность, но вероятность того, что вы получите ту же строку в вашем проекте, довольно мала.

0 голосов
/ 23 июня 2010

Если я хорошо понимаю, что вам нужно, основываясь на комментариях в двух таблицах, я думаю, вы сможете значительно упростить вашу проблему, если не объединять или не обновлять старую таблицу, потому что вам нужна новая таблица с идентификаторами в старые таблицы, когда они существуют, и новые идентификаторы, когда они не существуют, верно?

Новые записи: в таблице new уже есть новые записи - ОК (но им нужен новый идентификатор) Удаленные записи: их нет в новой таблице - ОК Обновленные записи: уже обновлены в новой таблице - ОК (нужно скопировать идентификатор из старой таблицы) Немодифицированные записи: уже в новой таблице - ОК (нужно скопировать идентификатор из старой таблицы)

Так что единственное, что вам нужно сделать, это: (a) скопировать идентификаторы из таблицы old в таблицу new, когда они существуют (б) создать новые идентификаторы в новой таблице, когда они не существуют в старой таблице (c) скопировать таблицу, новую для старой таблицы.

(a) ОБНОВЛЕНИЕ нового SET ID = IFNULL ((ВЫБЕРИТЕ ID ИЗ старого WHERE new.name = old.name), 0);

(b) ОБНОВИТЬ новый SET ID = FUNCTION_TO GENERATE_ID (new.name) WHERE ID = 0;

(c) Оставить старый стол; CREATE TABLE old (выберите * из нового);

Поскольку я не знаю, какую базу данных SQL вы используете, в (b) вы можете использовать функцию sql для генерации уникального идентификатора в зависимости от базы данных. С SQL Server newid (), с postgresql (не слишком старые версии), now () кажется хорошим выбором, поскольку его точность выглядит достаточной (но не в других базах данных, таких как MySQL, например, так как я думаю, что точность ограничена секундами)

Редактировать: Извините, я не видел, что вы используете sqlite и python. В этом случае вы можете использовать функцию str (uuid.uuid4 ()) (модуль uuid) в python, чтобы сгенерировать uuid и заполнить идентификатор в новой таблице, где ID = 0 на шаге (b). Таким образом, вы сможете при необходимости объединить 2 независимые базы данных без конфликтов по идентификаторам.

0 голосов
/ 17 июня 2010

черновой подход, я понятия не имею, работает ли он нормально ......

CREATE TRIGGER auto_next_id ПОСЛЕ INSERT ON таблица ДЛЯ КАЖДОГО РЯДА НАЧАЛО ОБНОВЛЕНИЕ таблицы SET uid = max (uid) + 1;END;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...