2009-07-06 4 views
0

Задача следующая:SQL: Как убедиться, что любой первичный ключ в любой таблице «принадлежит» известному идентификатору учетной записи (также PK) в верхней части иерархии?

Я отвечаю за создание интерфейса веб-сервисов для системы с огромной базой данных (сотни таблиц). Таблица верхнего уровня в базе данных - «Учетные записи» с первичным ключом Account_Id. Каждая строка в любой таблице может быть прослежена до одной учетной записи.

Каждая учетная запись должна иметь доступ к своей учетной записи через веб-службы.

Скажем, я создаю функцию веб-служб

DeleteProduct(string privateAccountKey, int productId); 

Как я могу убедиться, что - в общем автоматическом режиме - это продукт, который они пытаются удалить (кто первичный ключ ProductID) на самом деле принадлежит рассматриваемая учетная запись?


Update:

Спасибо за ваши быстрые ответы, но мне нужно более общее решение:

Допустим, у нас есть 10 вложенных таблиц A, B, C, D, E, F, G, Н, I, J. A - таблица верхнего уровня, B имеет внешний ключ в A, C имеет внешний ключ в B, D имеет внешний ключ в C и т. Д.

Учитывая только первичный ключ A и первичный ключ J, мы хотим удалить строку в J. Но мы хотим удостовериться, что строка, которую мы удаляем, принадлежит к строке в A, идентифицированной поставляемым основным ключом A. Это значит, что нам нужно «присоединиться» или «присоединиться», отслеживать назад "через внешние ключи от J до A, выяснить, какой первичный ключ в A первичный ключ из J связан и сравнить его с поставляемым первичным ключом из A, с которым мы должны убедиться, что это связано.

Можно ли это сделать в общем случае с помощью системных таблиц или чего-то еще? Нет жестко скопированных объединений и проверок. Он должен работать с любым количеством вложенных таблиц, учитывая только первичный ключ таблицы верхнего уровня в тандеме с первичным ключом таблицы нижнего уровня (или любой другой таблицы между ними).


Старый:

Я concernced, что они потенциально могут отправить по идентификаторам продукции, которая принадлежит другим счетам, и эти продукты будут получать удалены. Те же проблемы существуют с любым другим удалением или изменением данных.

Что мне нужно это хранимая процедура, которая принимает в качестве входных

а) имя таблицы и имя первичного ключа этой таблицы

б) первичный ключ сам из строки в этой таблице

с) идентификатор верхнего уровня первичного ключа

и выполняет:

d) выяснить, какие счета первичный ключ б) Б elongs к

е) возвращает истину, если учетная запись из г) совпадает с ID (и счета) из с)

Е.Г.:

PKBelongsToAccount(string table, string primaryKeyName, int ID, int accountId) 

Псевдо:

DeleteProduct(string privateAccountKey, int productId) 
{ 
    int accountId = FindAccountWhosPrivateKeyIs(privateAccountKey); 
    if (!PKBelongsToAccount("Products", "Product_Id", productId, accountId)) 
    { 
     return; 
    } 
    else 
    { 
     // Product can safely be deleted 
    } 
} 

Решить PKBelongsToAccount (как функции/процедуры SQL). Он должен отслеживать отношения базы данных через FK до тех пор, пока не попадет в таблицу Account, не узнает, на какой учетной записи она действительно принадлежит, и сравните ее с идентификатором учетной записи того, к чему мы хотим.

Возможно, есть лучшие способы сделать это.

Извините за беспорядок.

+0

В этом случае вам лучше разместить схему БД, чем ваш код. Можете ли вы дать представление о связанных таблицах и используемых ключах? – Eric

+0

Я обновил сообщение, которое должно сделать его более ясным, что я ищу. Благодарю. – Kurt

ответ

0

Вот моя лучшая попытка (без знания таблицы):

select * from products 
--delete from products 
where 
    productid = 1234 
    and exists (select 1 
       from 
        account_products a 
       where 
        a.productid = products.productid 
        and a.account = 4321) 

Он использует exists, чтобы найти его, так как я не знаю, что DB вы используете, так что это должно работать поперек доска. Кроме того, я прокомментировал delete, чтобы вы могли select сначала проверить, что он отводит правильные строки перед запуском delete. Это испытание, которое я от всей души рекомендую.

0

Пока я не знаю, что такое схема, вы должны быть уверены в существовании такой записи, прежде чем удалять ее.

Как и в вашем примере:

DeleteProduct(string privateAccountKey, int productId); 

переводит:

"удалить продукт заданного: privateAccountKey и ProductID"

так что вы должны быть в состоянии просто установить:

«выберите учетную запись, учитывая privateAccountKey и ProductID, используя предопределенный набор объединений»

Если это не дает никаких результатов - вы будете знать, что это неправильная команда. Очевидно, вам нужно будет заполнить соответствующие соединения в инструкции select.

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

1

Короткий ответ: да, вы могли бы делать то, что хотите.

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

Использование метода, такого как materialized path/adjacency list, позволит вам легко получить идентификатор родителя верхнего уровня, независимо от того, насколько глубоко вы идете.

+0

Спасибо за ваш вклад OrbMan, и большое спасибо за эту ссылку. Я многому научился, прочитав его. То же самое касается моего комментария к сообщению Тодда, все это ценный вклад, который в конечном итоге приведет к хорошему решению в системе, над которой я работаю, хотя я еще не совсем уверен, каким будет мое окончательное решение. – Kurt

1

Метаданные о таблицах, столбцах и ограничениях доступны из представлений SCHEMA (которые предположительно являются стандартом ISO). Например, ограничения внешнего ключа можно найти, запросив представление SCHEMA.REFERENTIAL _ СООТВЕТСТВИЯ.

Сложность, с которой вы столкнетесь, заключается в том, что каждая таблица, вероятно, имеет несколько ограничений внешнего ключа, поэтому как бы вы узнали, какой из них в конечном итоге приведет к таблице учетных записей? Другими словами, какой столбец ссылается на непосредственный родитель таблицы в «иерархии»? Если есть простой способ узнать это (например, всегда первый столбец в таблице), тогда все хорошо и хорошо, но если нет, то проблема эквивалентна поиску пути между двумя узлами в графе (на что я могу ответить просто один SQL-запрос ... больше похож на хранимую процедуру на 200 строк).

Таким образом, я ожидаю, что обобщенная процедура, основанная на информации _ SCHEMA, сама по себе будет сложной задачей. Было бы проще и надежнее просто создать свой собственный стол, чтобы описать эти метаданные, что-то вроде:

CREATE TABLE hierarchy (
    ChildTable sysname, 
    ParentTable sysname, 
    ChildColumn sysname, 
    ParentColumn sysname 
) 

Используя эти метаданные, вы можете либо запустить несколько соединений проследить вверх по иерархии, пока не дойдете таблицу счетов, или просто создайте один многозарядный JOIN для проверки.

+0

Спасибо Тодд, ваше сообщение имеет ценный вклад и помогает мне в организации проблемы в моей голове. И улучшение организации в вашей голове всегда в конечном итоге приводит к хорошему решению в конце, хотя я еще не совсем уверен, что я в итоге сделаю :) – Kurt

 Смежные вопросы

  • Нет связанных вопросов^_^