2010-02-08 19 views
6

necesito para modelar una idea que se pueden desglosar y el pensamiento de la siguiente manera:mejor enfoque para el almacenamiento de uno-muchos relación - Ejemplo práctico/Dilema

  1. BookDetails
  2. BookPrices

El problema aquí es que puede tener muchos precios para libros y es probable que estos precios cambien. Aquí hay un ejemplo

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

Esto es bastante fácil.

los casos en que es más interesante es que para éste libro que podría tener diez precios diferentes en ese día, por ejemplo:

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

necesito proporcionar una lista de libros y todos sus precios en columnas - algo como:

 
BookName   SpecialOffer BulkPurchase  Normal  
Harry Potter…    10    20   30 

Mi pregunta es: ¿debería la tabla de precios del libro en realidad tener todos los tipos de precios diferentes como columnas? Para mí esto es feo y una mejor idea es tener cada precio como una fila

Si utilizo ese enfoque no puedo pensar en una consulta SQL para generarme el conjunto de resultados. He estado pensando en esto toda la mañana.

EDITAR: No tengo margen de maniobra para calcular los precios; tienen que almacenarse.

EDIT: Este es básicamente el appraoch 1-n que puedo pensar (Gracias a comentar a continuación) - Es lo que en realidad tenía en mente

SELECT book.bookid, bp1.price, bp2.price DE libro ÚNASE a bookprice bp1 JOIN bookprice bp2 ON bp1.bookid = book.bookid AND bp1.pricetype = 1 AND bp2.bookid = book.bookid AND bp2.pricetype = 2 ...

El problema es que por diez precios usted estará unir diez veces lo que huele mal!

+0

¿Podría decirnos cuáles son los requisitos específicos y concretos para el esquema que está desarrollando? Algunas preguntas: ¿Necesita tener precios específicos por libro? ¿Habrá muchos tipos de ofertas? ¿Los tipos de oferta cambian con frecuencia? –

+0

Tengo control sobre cómo representar esto: puedo elegir una tabla 1-n (que prefiero hacer) pero no puedo pensar cómo puedo recuperar todos los precios en columnas para un libro. La alternativa es tener cada tipo de precio en una tabla y tener una asignación de 1-1 –

+1

Desea la capacidad de "** PIVOTAR **", que SQL Server no admite. SQL Server no puede generar columnas como esa. –

Respuesta

4

Esta respuesta es t-SQL específicos, y podrían utilizar un poco de refinamiento, pero funciona en SQL 2005.

Descomente las líneas de comentarios y a actualizar como magia! (Bueno, no es magia, pero 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 

/** este bit robado de 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

Desafortunadamente, cada vez que necesita hacer un pivote en un conjunto desconocido de columnas con valores desconocidos, debe usar SQL dinámico. Mi preferencia es tener un proceso "view builder" que tome los valores en las filas, se unen en tablas dinámicas y luego se reducen/crean vistas basadas en los nuevos valores. Muy similar a lo que está haciendo aquí, pero más sistemático. – jcollum

+0

Eso hace el trabajo - ¡Muy bien hecho! –

5

¿qué tal esto

BookDetails 
BookID BookName 

BookPrice 
BookID PriceID PriceTypeID 

BookPriceType 
PriceTypeID DEscription 
+0

Ok - ¿Cuál es la consulta para mostrarme todos los precios (incluso si son nulos) para un libro? Esa es la parte difícil –

+0

Esto huele mucho a la tarea. – Tomalak

+2

Definitivamente no lo es - Mi pregunta es cómo puedo representar esto como una relación 1-n y absorber todos los precios como COLUMNS –

0

Si desea almacenar los precios de forma estática (en lugar de, por ejemplo calcularlos), utiliza un 1-a-n-relación:

Tabla 1 con filas: Identificación Título Editorial etc.

Tabla 2 con filas: bookId Precio

"BookID" de la Tabla 2 apuntará a "ID" de la Tabla 1, de esta manera puede tener tantos precios como desee. Use JOIN (consulte la documentación de SQL) para recuperar todos los precios de un libro específico.

Si ofrece descuentos especiales (por ejemplo, compra al por mayor 10% de descuento, pero 20% de descuento si el cliente compra más de 100 artículos a la vez), prefiero calcular el precio en lugar de almacenarlo estáticamente.

+0

El uso de 3 tablas (como se sugiere en otras respuestas) solo es necesario, si también desea volver a utilizar precios para otros libros (un precio solo se almacena una vez). Pero de esta manera, usted cambiará ese precio específico para TODOS los libros si lo modifica. – Select0r

0

Este es un caso de uso básico para una mesa de juego donde usted tiene:

1 mesa para información sobre el libro
1 mesa para más informaciones:
mesa 1 puente para unir las dos juntas para cada instancia del libro y precio.

1

Me he enfrentado a este problema similar muchas veces. Tal como lo veo, ¿puedes modelar explícitamente un libro? Entonces, por ejemplo, tiene 10 tipos de precios. ¿Son estos tipos estáticos? ¿Alguna vez cambian? Si no cambian, prefiero tenerlos como columnas, en un precio (no lo llamaría detalles). Eso incluiría una fecha de inicio efectiva y una fecha de finalización opcional. Esto le permitiría manejar cambios de precios por etapas antes de tiempo.

Ahora, si no conoce los tipos de precios que maneja. Un ejemplo sería un sistema en el que un usuario final (un usuario de administración más probable) definiría los libros y los diversos tipos de precios. Este es un sistema significativamente más complejo porque también necesitaría permitir que el usuario defina las reglas a la hora de usar qué precio.

actualización

He aquí un ejemplo del uso de una consulta cruzada dinámica:

crear #BookPrice tabla (int bookId, dinero Precio, nvarchar PriceType (30)) inserción en #BookPrice valores (1,10.55, 'Lista')

inserción en #BookPrice valores (1,9.50, 'Coste') inserción en #bookPrice valores (2,10.22, 'Lista')

/averiguar qué precios que necesita .... PROBally no por la consulta de la propia tabla/ varchar declarar @priceQuery (max) seleccione @priceQuery = IsNull (@priceQuery, '') + '[ '+ fundido (PriceType como varchar (32)) + '],' de (seleccione PriceType distinta de #BookPrice ) p

- Retirar última coma establecer @priceQuery = izquierda (@ priceQuery, len (@priceQuery) -1)

declare @dynq uery varchar (max) conjunto @dynquery = 'seleccionar bookId, *' + 'de #BookPrice' + 'pivote (' + 'max ([Precio])' + 'para [PriceType]' + ' en (' + @priceQuery + ')) como tabla dinámica'

exec (@dynquery)

tabla de la gota #bookPrice

ACTUALIZACIÓN

actualizado la muestra anterior para mostrar ho w si usted tiene un libro al que le falta un tipo de precio que se mostrará como nulo en la consulta

+0

Eso es exactamente el problema aquí - podría tener MUCHOS precios para un libro y eso es lo que no puedo modelar –

1

La pregunta aquí es:

Wil lista lthe de Reserva Precio ser estático?o son los tipos de precios (precio del día de Columbus, precio especial de Superbowl XXXVIII, porque me gusta el precio de los martes, van a aparecer con frecuencia y desaparecen?

Si la lista es estática, (digamos 5 o 6 tipos diferentes de precios, luego ponga a cada uno en una columna adicional en la tabla de productos.

Si la lista se puede cambiar (aunque sólo ligeramente y/o con muy poca frecuencia) a continuación, añadir una tabla separada para los precios.

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

Como otros tienen mencionado, si almacena los datos como filas dentro de su tabla, tendrá más flexibilidad si surge la necesidad de más tipos de precios. Siempre que utilice este enfoque, lo más probable es que necesite girar los datos para generar los resultados con una fila por libro con todas las diversas opciones de precios incluidas en la misma fila (como su ejemplo implícito). Dependiendo de la versión de SQL Server que esté utilizando, esto puede ser relativamente trivial de implementar, o puede ser un poco más desafiante. Consulte esto SO question para más detalles.

Si los tipos de precios son estáticos, es mejor que los guarde simplemente almacenando los datos como columnas de la tabla en lugar de filas. Esto hace que sea trivial devolver los datos en la forma que está buscando, a costa de un poco más de trabajo si las reglas cambian. Lo siento por leer mal la pregunta

Puede usar tres tablas aquí para representar a modelar, uno de los libros::

CREATE TABLE Books (
BookId Int, 
Name Varchar 
) 

uno para los precios:

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

y uno

0
Editar

para unirlos todos juntos (esto tiene una bandera para mostrar el precio actual):

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

El PriceName proporciona un enlace para una consulta dinámica, que convertirá sus filas en columnas. En mi prueba utilicé los nombres Shelf y 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

¡Eso me da precios como FILAS !! Los necesito como columnas :( –

0

Creo que he tenido un problema similar.
I solucionado esto con el T-SQL de construcción 'pivote'
(fealdad: hay que indicar explícitamente las columnas de la consulta)

Estamos utilizando T-SQL.
No conozco el dialecto sql que está utilizando, por lo que es posible que no sea aplicable.

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

0

Esto quizás podría hacer lo que desea.

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] 

Solo asegúrese de que los nombres de columna se adapten a los suyos y debería hacerlo. Además, es ANSI, por lo tanto, este no es un código SQL SQL específico de DBMS y se puede usar en ORACLE, SQL SERVER, etc.

Cuestiones relacionadas