brux88 ha scritto:
Ciao, grazie per il suggerimento ;) so che non e proponibile una tabella del genere infatti sto cercando di rimodellarla. Per normalizzazione si intende evitare le duplicazioni delle proprieta ad esempio tutti i dati del cliente metterli in una tabella separata e mettere solo il riferimento id nella tabella principale giusto ?
tendenzialmente, si :)
Quindi per ogni riga di fattura avro una tabella con ogni riga del cliente corrispondente oppure metterò l'id di riferimento della tabella clienti principale quella delle anagrafcihe?
metterai l'id... vedi "normalizzazione"
Però adottando l'ultimo caso se io faccio una fattura con cliente 1 Rossi è ha un indirizzo, poi dopo qualche mese Rossi cambia indirizzo, quindi vado nell'anagrafica di rossi e modifico l'indirizzo, id cliente rimane sempre 1, ma se poi stampo una fattura vecchia mi deve stampare con l'indirizzo vecchio, perche in quel momento aveva quell'indirizzo per questo non ho normalizzato la tabella e mi sono riportato tutto dietro cosi quella fattura rimarrà cosi a prescindere dalle modifiche che effettuerò nelle anagrafiche dei clienti, ditte,banca etc...
Il mio problema sta proprio qui... capire come poter normalizzare le tabelle se ho queste necessita...
Modificato da brux88 il 27 febbraio 2017 08.39 -
in questi casi ti serve una struttura temporale... cioe' con validita' legata ad una finestra temporale...
id: 1 - Nome: Andrea Montanari - citta': Riccione - dal: 01/01/1965 al: NULL
id: 2 - Nome: Brux88 - citta': Roma - dal: 01/01/2000 al: 31/12/2015
id: 2 - Nome: Brux88 - citta': Milano - dal: 01/01/2006 al: NULL
o simile indica che Andrea Montanari abita da sempre a Riccione, mentre Brux88 abitava a Roma dal 01/01/2000 al 31/12/2015, e quindi si e' trasferito a Milano...
(ovviamente anche questa struttura va normalizzata, quindi avrai in questo caso una tabella Indirizzo che relaziona 1 a molti con la tabella anagrafica)
la tua query per ottenere l'indirizzo, dovra' passara una data di riferimento..
quindi la query per l'acquisto di Brux88 effettuato nel 2014 referenziera' Roma, mentre l'acquisto del 2016 Milano...
si, lo so, i database temporali sono complicati e pesanti, pero' funzionano cosi'...
SQL Server 2016 ha introdotto delle novita' in questo senso, pero'...
al di la' di cio', trivialmente, si puo' fare ad esempio utilizzando anche la windowing function LEAD https://msdn.microsoft.com/it-it/library/hh213125.aspx
SET NOCOUNT ON;
USE tempdb;
GO
CREATE TABLE dbo.Anagrafica (
Id int NOT NULL PRIMARY KEY,
Nome varchar(15),
PIVA varchar(11)
);
CREATE TABLE dbo.Ana_Indirizzi (
IdCliente int NOT NULL
CONSTRAINT fk_Ana_Indir$is$Anagrafica FOREIGN KEY
REFERENCES dbo.Anagrafica (Id),
Citta varchar(10),
ValidoDal date NOT NULL,
-- NELLA REALTA' del design temporale, questo attributo ci vuole
-- ma se e' sufficiente l'indicatore del PROSSIMO [ValidoDal]
-- si puo' anche omettere
ValidoAl date NULL
);
CREATE TABLE dbo.Fatture (
Id int NOT NULL IDENTITY PRIMARY KEY,
Data date NOT NULL,
Numerazione varchar(20),
Altro varchar(10),
IdCliente int NOT NULL
CONSTRAINT fk_Fatture$has$Anagrafica FOREIGN KEY
REFERENCES dbo.Anagrafica (Id)
);
GO
INSERT INTO dbo.Anagrafica
VALUES (1, 'Andrea', '01000000000');
INSERT INTO dbo.Ana_Indirizzi
VALUES (1, 'Riccione', '1965-10-30', NULL);
INSERT INTO dbo.Anagrafica
VALUES (2, 'Brux88', '01000000001');
INSERT INTO dbo.Ana_Indirizzi
VALUES (2, 'Roma', '1988-01-01', '2015-12-31');
INSERT INTO dbo.Ana_Indirizzi
VALUES (2, 'Milano', '2016-01-01', NULL);
INSERT INTO dbo.Fatture
VALUES ('2010-01-11', '12345/e', 'Altro', 1),
('2011-01-01', '1/a', 'Altro1', 1),
('2014-01-01', '1/a', 'Altro2', 1),
('2016-01-01', '1/a', 'Altro3', 1),
('2017-01-01', '1/a', 'Altro4', 1);
INSERT INTO dbo.Fatture
VALUES ('2010-01-11', '12346/e', 'Altro10', 2),
('2011-01-01', '2/a', 'Altro11', 2),
('2014-01-01', '2/a', 'Altro12', 2),
('2016-01-01', '2/a', 'Altro13', 2),
('2017-01-01', '2/a', 'Altro14', 2);
GO
PRINT 'Elenco clienti';
SELECT *
FROM dbo.Anagrafica a
JOIN dbo.Ana_Indirizzi ai ON ai.IdCliente = a.Id;
PRINT 'Elenco indirizzi clienti';
WITH cteAnaInd AS (
SELECT ai.IdCliente, ai.Citta
, ai.ValidoDal
, CONVERT(date, ISNULL(LEAD (ai.ValidoDal, 1) OVER (PARTITION BY ai.IdCliente ORDER BY ai.ValidoDal), GETDATE())) AS ValidoAl
FROM dbo.Anagrafica a
JOIN dbo.Ana_Indirizzi ai ON ai.IdCliente = a.Id
)
SELECT *
FROM cteAnaInd;
PRINT 'Elenco fatture e relativi indirizzi clienti';
WITH cteAnaInd AS (
SELECT ai.IdCliente, ai.Citta
, ai.ValidoDal
, CONVERT(date, ISNULL(LEAD (ai.ValidoDal, 1) OVER (PARTITION BY ai.IdCliente ORDER BY ai.ValidoDal), GETDATE())) AS ValidoAl
FROM dbo.Anagrafica a
JOIN dbo.Ana_Indirizzi ai ON ai.IdCliente = a.Id
)
SELECT f.Id, f.Data, f.Numerazione, f.Altro
, a.Nome, a.PIVA
, ai.Citta
FROM dbo.Fatture f
JOIN dbo.Anagrafica a ON a.Id = f.IdCliente
JOIN cteAnaInd ai ON ai.IdCliente = a.Id
AND (f.Data BETWEEN ai.ValidoDal AND ai.ValidoAl)
ORDER by f.IdCliente, f.Data;
GO
DROP TABLE dbo.Fatture, dbo.Ana_Indirizzi, dbo.Anagrafica
--<-----------
Elenco clienti
Id Nome PIVA IdCliente Citta ValidoDal ValidoAl
----------- --------------- ----------- ----------- ---------- ---------- ----------
1 Andrea 01000000000 1 Riccione 1965-10-30 NULL
2 Brux88 01000000001 2 Roma 1988-01-01 2015-12-31
2 Brux88 01000000001 2 Milano 2016-01-01 NULL
Elenco indirizzi clienti
IdCliente Citta ValidoDal ValidoAl
----------- ---------- ---------- ----------
1 Riccione 1965-10-30 2017-03-07
2 Roma 1988-01-01 2016-01-01
2 Milano 2016-01-01 2017-03-07
Elenco fatture e relativi indirizzi clienti
Id Data Numerazione Altro Nome PIVA Citta
----------- ---------- -------------------- ---------- --------------- ----------- ----------
1 2010-01-11 12345/e Altro Andrea 01000000000 Riccione
2 2011-01-01 1/a Altro1 Andrea 01000000000 Riccione
3 2014-01-01 1/a Altro2 Andrea 01000000000 Riccione
4 2016-01-01 1/a Altro3 Andrea 01000000000 Riccione
5 2017-01-01 1/a Altro4 Andrea 01000000000 Riccione
6 2010-01-11 12346/e Altro10 Brux88 01000000001 Roma
7 2011-01-01 2/a Altro11 Brux88 01000000001 Roma
8 2014-01-01 2/a Altro12 Brux88 01000000001 Roma
9 2016-01-01 2/a Altro13 Brux88 01000000001 Roma
9 2016-01-01 2/a Altro13 Brux88 01000000001 Milano
10 2017-01-01 2/a Altro14 Brux88 01000000001 Milano
salutoni
Modificato da Andrea Montanari il 07 marzo 2017 18.53 -