2010-02-08 2 views
6

мне нужно моделировать идею, которая может быть нарушена вниз и мысль о том, как следует:Лучший подход для хранения одного-многим - Практический пример/Дилемма

  1. BookDetails
  2. BookPrices

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

 
BookDetails: 
----------------- 
ID Name 
1 Harry Potter… 

Это достаточно легко.

Где это более интересно то, что для одной этой книги я мог бы иметь десять различных цен на тот же день, например:

 
BookPrices: 
------------------------------------ 
Book_Details_Id Kind   Price 
1    SpecialOffer  10 
1    BulkPurchase  20 
1    Normal   30 

мне нужно предоставить список книг и все их цены в столбцах - что-то например:

 
BookName   SpecialOffer BulkPurchase  Normal  
Harry Potter…    10    20   30 

Мой вопрос: стоит ли в книжной ценовой таблице все разные типы цен в качестве столбцов? Для меня это некрасиво, и лучшая идея состоит в том, чтобы иметь каждую цену как строку

Если я использую этот подход, я не могу придумать SQL-запрос, чтобы сгенерировать мне результирующий набор. Я думал об этом все утро.

EDIT: У меня нет возможности рассчитывать цены - их нужно хранить.

EDIT: Это в основном 1-н appraoch я могу думать (спасибо комментарий ниже) - Его, что я на самом деле имел в виду

ВЫБРАТЬ book.bookid, bp1.price, bp2.price из книги JOIN bookprice bp1 JOIN bookprice bp2 ON bp1.bookid = book.bookid AND bp1.pricetype = 1 AND bp2.bookid = book.bookid AND bp2.pricetype = 2 ...

Проблема заключается в десяти ценах, которые вы будете вступая в десятку раз, что воняет!

+0

Не могли бы вы рассказать нам, каковы конкретные и конкретные требования к схеме, которую вы разрабатываете? Некоторые вопросы: нужны ли вам конкретные цены за книгу? Будет ли много предложений? Часто ли меняются типы предложений? –

+0

У меня есть контроль над тем, как это представить - я могу либо выбрать таблицу 1-n (что я предпочитаю делать), но я не могу представить, как я могу получить все цены в столбцах для одной книги. Альтернативой является наличие каждого типа цены в таблице и отображение 1-1. –

+1

Вы хотите использовать функцию «** PIVOT **», которую SQL Server не поддерживает. SQL Server не может создавать такие столбцы. –

ответ

4

Этот ответ T-SQL специфичным и может использовать немного утонченности, но он работает на SQL 2005.

Раскомментируем комментировал линий, и это будет обновлять, как по волшебству! (Хорошо, не магия, но niftily Hacky)

DROP TABLE Books 
DROP TABLE Prices 
DROP TABLE bookpricing 

CREATE TABLE Books (id INT, title VARCHAR(20)) 
CREATE TABLE Prices (id INT, [desc] VARCHAR(20), pricingchange VARCHAR(20)) 
CREATE TABLE bookpricing (id INT, bookid INT, priceid INT, bookprice MONEY) 

INSERT INTO Books VALUES (1, 'Hi Mom') 
--INSERT INTO Books Values (2, 'This is another book') 
INSERT INTO Prices VALUES (1, 'Standard', '1') 
INSERT INTO Prices VALUES (2, 'Discount', '.5') 
INSERT INTO Prices VALUES(3, 'HyperMarkup', '1.5') 
INSERT INTO prices VALUES(4, 'Remaindered', '.1') 

INSERT INTO BookPricing VALUES (1,1,1,20.00) 
INSERT INTO BookPricing VALUES (2,1,2,10.00) 
INSERT INTO BookPricing VALUES (3,1,3,30.00) 
--INSERT INTO BookPricing VALUES (4,2,1,30.00) 
--INSERT INTO BookPricing VALUES (5,2,2,15.00) 
--INSERT INTO BookPricing VALUES (6,2,4,3.00) 

SELECT * FROM bookpricing 

/** этот бит украдена из http://www.tsqltutorials.com/pivot.php **/

DECLARE @columns VARCHAR(max) 

SELECT @columns = COALESCE(@columns + ',[' + cast(id as varchar) + ']', 
'[' + cast(id as varchar)+ ']') 
FROM prices 


DECLARE @query VARCHAR(max) 

SET @query = ' 
SELECT * FROM (SELECT BookID, PriceID, BookPrice FROM BookPricing) AS BookTable PIVOT (SUM(bookprice) FOR priceid 
IN (' + @columns + ') 
) 
AS p' 

EXECUTE(@query) 
+2

К сожалению, в любое время, когда вам нужно выполнить поворот на неизвестном наборе столбцов с неизвестными значениями, вам нужно использовать динамический SQL. Мое предпочтение состоит в том, чтобы обработать «конструктор представлений», который принимает значения в строки, объединяются в сводные таблицы, затем отбрасывает/создает представления на основе новых значений. Очень похоже на то, что вы здесь делаете, но более систематично. – jcollum

+0

Это делает работу - отлично! –

5

как об этом

BookDetails 
BookID BookName 

BookPrice 
BookID PriceID PriceTypeID 

BookPriceType 
PriceTypeID DEscription 
+0

Ok - Какой запрос должен показывать мне все цены (даже если null) для одной книги? Thats трудная часть –

+0

Это пахнет очень как домашнее задание. – Tomalak

+2

Это определенно не так. Мой вопрос заключается в том, как я могу представить это как отношение 1-n и высасывать все цены, так как COLUMNS –

0

Если вы хотите сохранить цены статически (например, вместо расчета их), используйте 1-к-н-связь:

Таблица 1 с рядами: ID Название Издательство т.д.

Таблица 2 со строками: BookID Цена

«BookID» из таблицы 2 будет указывать на «ID» из таблицы 1, таким образом вы можете иметь столько цен, сколько хотите. Используйте JOIN (см. SQL-документацию), чтобы получить все цены за определенную книгу.

Если вы предлагаете специальные скидки (например, навалом 10% скидка, но 20% скидка, если клиент покупает более 100 предметов за раз), я бы скорее вычислил цену, а не статировал ее.

+0

Использование 3 таблиц (как предлагается в других ответах) необходимо только, если вы также хотите повторно использовать цены на другие книги (одна цена хранится только один раз). Но таким образом вы измените эту конкретную цену для ВСЕХ книг, если вы ее измените. – Select0r

0

Это базовый вариант использования для таблицы моста, где у вас есть:

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

1

Я столкнулся с подобной проблемой много раз. То, как я смотрю на это, - это вы можете явно составить книгу. Так, например, у вас есть 10 типов цен. Являются ли эти типы статическими? Они когда-нибудь меняются? Если они не меняются, я предпочитаю иметь их как столбцы, в ценообразовании (не будем называть его подробностями). Это будет включать эффективную дату начала и дополнительную дату окончания. Это позволит вам своевременно обрабатывать изменения ценообразования.

Теперь, если вы не знаете цены, с которыми имеете дело. Примером может служить система, в которой конечный пользователь (скорее всего, пользователь Admin) будет определять книги и различные типы цен. Это значительно более сложная система, потому что вы также должны позволить пользователю определять правила, когда использовать эту цену.

Update

Вот пример использования динамического поворота запрос:

создать таблицу #BookPrice (BookID Int, цена денег, PriceType NVARCHAR (30)) вставки в значениях #BookPrice (1,10.55, 'Список')

вставка в значения #BookPrice (1,9.50, 'Стоимость') вставка в значения #bookPrice (2,10.22, 'Список')

/Выяснить какие цены вам нужно .... прочертовский не опрашивать сама таблица/ объявить @priceQuery VARCHAR (макс) выберите @priceQuery = IsNull (@priceQuery, '') + «[ '+ литье (PriceType, как VARCHAR (32)) +],' из (выбрать отличный от PriceType #BookPrice ) р

- Удалить последнюю запятой установить @priceQuery = левый (@ priceQuery, Len (@priceQuery) -1)

Объявление @dynq uery VARCHAR (макс) множество @dynquery = 'выберите BookID, *' + 'от #BookPrice' + 'поворота (' + 'макс ([Цена])' + 'для [PriceType]' + ' в (»+ @priceQuery + ')) в качестве сводной таблицы'

Exec (@dynquery)

падение стол #bookPrice

ОБНОВЛЕНИЕ

Обновленный выше образец, чтобы показать хо ж, если у вас есть книга, который отсутствует тип цен, который будет отображаться как нуль в запросе

+0

Thats точно проблема здесь - у меня могло бы быть МНОГО цен для одной книги и thats то, что я не могу модель –

1

Вопрос здесь:

Wil lthe список типов Книга Цена статическими?или являются типами цен (цена на Columbus Day, Special Superbowl XXXVIII Цена, причина, по которой мне нравится вторник Цена, часто появляется и исчезает?

Если список статичен (скажем, 5 или 6 разных типов цен, их каждый в отдельной колонке в таблице продуктов.

Если список может измениться (даже если только чуть-чуть и/или очень редко), а затем добавить отдельную таблицу для цен.

Create Table Prices (
    ProductId Integer Not Null, 
    PriceTypeId Integer Not Null, 
    Price Decimal(16,4) Not Null, 
    Primary Key Constraint PricePK (ProductId, PriceTypeId) 
    ) 
2

Как другие если вы храните данные в виде строк в своей таблице, у вас будет больше гибкости, если возникнет потребность в более высоких ценовых типах. когда-либо используя этот подход, скорее всего, вам понадобится сворачивать данные, чтобы выводить результаты с одной строкой в ​​каждой книге со всеми различными параметрами ценообразования, включенными в ту же строку (как предположил ваш пример). В зависимости от того, какая версия SQL Server, которую вы используете, может быть относительно тривиальной для реализации, или она может быть более сложной. См. Это SO question для более подробной информации.

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

0

Edit: Извините за неправильное вопрос

Вы можете использовать три таблицы здесь, чтобы представить вам модель, один для книг:

CREATE TABLE Books (
BookId Int, 
Name Varchar 
) 

один для цен:

CREATE TABLE Prices (
PriceId Int, 
Amount decimal, 
PriceName varchar 
) 

и один (для этого есть флаг, показывающий текущую цену):

CREATE TABLE BookPrices (
BookId Int, 
PriceId Int, 
Current bit 
) 

PriceName обеспечивает крючок для сводного запроса, который превратит ваши строки в столбцы. В своем тесте я использовал имена Shelf и Online

SELECT * 
FROM (
    SELECT Book.Name BookName, Price.Amount Amount, Price.Name PriceName 
    FROM Books Book 
    JOIN BookPrices bp 
     ON Book.BookId = bp.BookId 
    JOIN Prices Price 
     ON Price.PriceId = bp.PriceId 
) DataTable 
PIVOT(
    SUM(Amount) 
    FOR PriceName IN ([Shelf],[Online]) 
) PivotTable 
+0

Это дает мне цены как ROWS !! Мне нужно, чтобы они были в виде столбцов :( –

0

Я думаю, что у меня была схожая проблема.
Я решил эту проблему с T-SQL строительства «оси»
(уродства: вы должны явно указать столбцы в запросе)

Мы используем T-SQL.
Я не знаю диалект sql, который вы используете, поэтому он может быть неприменим.

http://www.tsqltutorials.com/pivot.php

0

Это может возможно сделать то, что вы хотите.

SELECT D.ID, D.[NAME] 
, SUM(D.SpecialOffer) AS SpecialOffer 
, SUM(D.BulkPrice) AS BulkPrice 
, SUM(D.Normal) AS Normal 
FROM (
SELECT BD.ID AS ID, BD.NAME AS [NAME] 
    , CASE WHEN BP.Kind LIKE N'%SpecialOffer%' THEN BP.Price ELSE NULL END AS SpecialOffer 
    , CASE WHEN BP.Kind LIKE N'%BulkPrice%' THEN BP.Price ELSE NULL END AS BulkPrice 
    , CASE WHEN BP.Kind LIKE N'%Normal%' THEN BP.Price ELSE NULL END AS Normal 
FROM BookDetails BD 
INNER JOIN BookPrices BP ON BP.ID_BOOK_DETAILS = BD.ID) D 
GROUP BY D.ID, D.[NAME] 

Просто убедитесь, что имена колонок соответствуют вашим требованиям, и он должен это сделать. Кроме того, это ANSI, поэтому это не SQL-код SQL SQL, и его можно использовать в ORACLE, SQL SERVER и т. Д.

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