sql server programming:
Hi all, I am trying to create an indexed view to do aggregation on a table of Payments. The table has columns as follows: CREATE TABLE [Payments] ( [PmtKey] [int] IDENTITY (1, 1) NOT NULL , [PmtAmt] [smallmoney] NOT NULL , [PmtDate] [smalldatetime] NOT NULL , [Voided] [bit] NOT NULL CONSTRAINT [DF_Payments_Voided] DEFAULT (0), CONSTRAINT [PK_Payments] PRIMARY KEY CLUSTERED ( [PmtKey] ) ON [PRIMARY] ) ON [PRIMARY] I am trying to create an indexed view as follows: CREATE VIEW dbo.vwPayments_ByDate WITH SCHEMABINDING AS SELECT CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, SUM(PmtAmt) AS DaysPmts, COUNT_BIG (*) AS Expr1 FROM dbo.Payments WHERE (Voided = 0) GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) I am doing the cast to try to get all payments grouped by the same date, ignoring the time portion. When I go to add a unique clustered index to this view, CREATE UNIQUE CLUSTERED INDEX [PK_vwPmts_ByDate] ON [dbo].[vwPayments_ByDate] ([PmtDate]) WITH FILLFACTOR = 85 I am told that the column PmtDate is non-detereministic or too imprecise. I understand the requirement that the indices in an indexed view cannot be nullable and must be deterministic. Is there another way to cast PmtDate that will allow me to do the grouping and aggregation I am trying to achieve? Thanks. --
Thanks Dan, From BOL: CONVERT: Deterministic unless used with datetime, smalldatetime, or sql_variant. The datetime and smalldatetime data types are deterministic if the style parameter is also specified. In theory, it would sure seem that your solution should work. In practice, I get the same error. Any other thoughts? -- John [quoted text, click to view] "Dan Guzman" wrote: > > Is there another way to cast PmtDate > > that will allow me to do the grouping and aggregation I am trying to > > achieve? > > CAST is non-deterministic when used with smalldatetime. Try CONVERT with a > style parameter instead: > > CONVERT(smalldatetime, DATEDIFF(DAY, 0, PmtDate), 112) > > -- > Hope this helps. > > Dan Guzman > SQL Server MVP > > "JT" <Jthayer@online.nospam> wrote in message > news:2DA1D643-75AC-4B61-AE2C-E08C3085F5A7@microsoft.com... > > Hi all, > > I am trying to create an indexed view to do aggregation on a table of > > Payments. The table has columns as follows: > > > > CREATE TABLE [Payments] ( > > [PmtKey] [int] IDENTITY (1, 1) NOT NULL , > > [PmtAmt] [smallmoney] NOT NULL , > > [PmtDate] [smalldatetime] NOT NULL , > > [Voided] [bit] NOT NULL CONSTRAINT [DF_Payments_Voided] DEFAULT (0), > > CONSTRAINT [PK_Payments] PRIMARY KEY CLUSTERED > > ( > > [PmtKey] > > ) ON [PRIMARY] > > ) ON [PRIMARY] > > > > I am trying to create an indexed view as follows: > > > > CREATE VIEW dbo.vwPayments_ByDate > > WITH SCHEMABINDING > > AS > > SELECT > > CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, > > SUM(PmtAmt) AS DaysPmts, > > COUNT_BIG (*) AS Expr1 > > > > FROM dbo.Payments > > WHERE (Voided = 0) > > GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) > > > > I am doing the cast to try to get all payments grouped by the same date, > > ignoring the time portion. > > When I go to add a unique clustered index to this view, > > > > CREATE UNIQUE CLUSTERED > > INDEX [PK_vwPmts_ByDate] ON [dbo].[vwPayments_ByDate] ([PmtDate]) > > WITH > > FILLFACTOR = 85 > > > > I am told that the column PmtDate is non-detereministic or too imprecise. > > I understand the requirement that the indices in an indexed view cannot be > > nullable and must be deterministic. Is there another way to cast PmtDate > > that will allow me to do the grouping and aggregation I am trying to > > achieve? > > > > Thanks. > > -- > > John > >
[quoted text, click to view] > Is there another way to cast PmtDate > that will allow me to do the grouping and aggregation I am trying to > achieve?
CAST is non-deterministic when used with smalldatetime. Try CONVERT with a style parameter instead: CONVERT(smalldatetime, DATEDIFF(DAY, 0, PmtDate), 112) -- Hope this helps. Dan Guzman SQL Server MVP [quoted text, click to view] "JT" <Jthayer@online.nospam> wrote in message news:2DA1D643-75AC-4B61-AE2C-E08C3085F5A7@microsoft.com... > Hi all, > I am trying to create an indexed view to do aggregation on a table of > Payments. The table has columns as follows: > > CREATE TABLE [Payments] ( > [PmtKey] [int] IDENTITY (1, 1) NOT NULL , > [PmtAmt] [smallmoney] NOT NULL , > [PmtDate] [smalldatetime] NOT NULL , > [Voided] [bit] NOT NULL CONSTRAINT [DF_Payments_Voided] DEFAULT (0), > CONSTRAINT [PK_Payments] PRIMARY KEY CLUSTERED > ( > [PmtKey] > ) ON [PRIMARY] > ) ON [PRIMARY] > > I am trying to create an indexed view as follows: > > CREATE VIEW dbo.vwPayments_ByDate > WITH SCHEMABINDING > AS > SELECT > CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, > SUM(PmtAmt) AS DaysPmts, > COUNT_BIG (*) AS Expr1 > > FROM dbo.Payments > WHERE (Voided = 0) > GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) > > I am doing the cast to try to get all payments grouped by the same date, > ignoring the time portion. > When I go to add a unique clustered index to this view, > > CREATE UNIQUE CLUSTERED > INDEX [PK_vwPmts_ByDate] ON [dbo].[vwPayments_ByDate] ([PmtDate]) > WITH > FILLFACTOR = 85 > > I am told that the column PmtDate is non-detereministic or too imprecise. > I understand the requirement that the indices in an indexed view cannot be > nullable and must be deterministic. Is there another way to cast PmtDate > that will allow me to do the grouping and aggregation I am trying to > achieve? > > Thanks. > -- > John
It looks like you are using SQL 2000. Erland posted one method that will work in SQL 2000. Here's an extention of that technique that will return a smalldatetime: CONVERT(smalldatetime, CONVERT(char(8), PmtDate, 112), 112) AS PmtDate -- Hope this helps. Dan Guzman SQL Server MVP [quoted text, click to view] "JT" <Jthayer@online.nospam> wrote in message news:11FDCEC3-F22E-4572-B211-AF822FCCC5AC@microsoft.com... > Thanks Dan, > From BOL: > CONVERT: Deterministic unless used with datetime, smalldatetime, or > sql_variant. The datetime and smalldatetime data types are deterministic > if > the style parameter is also specified. > In theory, it would sure seem that your solution should work. In > practice, > I get the same error. Any other thoughts? > -- > John > > > "Dan Guzman" wrote: > >> > Is there another way to cast PmtDate >> > that will allow me to do the grouping and aggregation I am trying to >> > achieve? >> >> CAST is non-deterministic when used with smalldatetime. Try CONVERT with >> a >> style parameter instead: >> >> CONVERT(smalldatetime, DATEDIFF(DAY, 0, PmtDate), 112) >> >> -- >> Hope this helps. >> >> Dan Guzman >> SQL Server MVP >> >> "JT" <Jthayer@online.nospam> wrote in message >> news:2DA1D643-75AC-4B61-AE2C-E08C3085F5A7@microsoft.com... >> > Hi all, >> > I am trying to create an indexed view to do aggregation on a table of >> > Payments. The table has columns as follows: >> > >> > CREATE TABLE [Payments] ( >> > [PmtKey] [int] IDENTITY (1, 1) NOT NULL , >> > [PmtAmt] [smallmoney] NOT NULL , >> > [PmtDate] [smalldatetime] NOT NULL , >> > [Voided] [bit] NOT NULL CONSTRAINT [DF_Payments_Voided] DEFAULT (0), >> > CONSTRAINT [PK_Payments] PRIMARY KEY CLUSTERED >> > ( >> > [PmtKey] >> > ) ON [PRIMARY] >> > ) ON [PRIMARY] >> > >> > I am trying to create an indexed view as follows: >> > >> > CREATE VIEW dbo.vwPayments_ByDate >> > WITH SCHEMABINDING >> > AS >> > SELECT >> > CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, >> > SUM(PmtAmt) AS DaysPmts, >> > COUNT_BIG (*) AS Expr1 >> > >> > FROM dbo.Payments >> > WHERE (Voided = 0) >> > GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) >> > >> > I am doing the cast to try to get all payments grouped by the same >> > date, >> > ignoring the time portion. >> > When I go to add a unique clustered index to this view, >> > >> > CREATE UNIQUE CLUSTERED >> > INDEX [PK_vwPmts_ByDate] ON [dbo].[vwPayments_ByDate] ([PmtDate]) >> > WITH >> > FILLFACTOR = 85 >> > >> > I am told that the column PmtDate is non-detereministic or too >> > imprecise. >> > I understand the requirement that the indices in an indexed view cannot >> > be >> > nullable and must be deterministic. Is there another way to cast >> > PmtDate >> > that will allow me to do the grouping and aggregation I am trying to >> > achieve? >> > >> > Thanks. >> > -- >> > John >> >> >>
Dan and Erland, Thank you both for your posts and wisdom. I independently got it working by getting rid of the 0 and explicitly setting 1/1/1900 as the index date for SQL Server's Datediff function. For example: CREATE VIEW dbo.vwPayments_ByDate WITH SCHEMABINDING AS SELECT CONVERT(smalldatetime, DATEDIFF([DAY], CONVERT(DATETIME, '1900-01-01 00:00:00', 102), PmtDate), 101) AS PmtDate, SUM(PmtAmt) AS DaysPmts, COUNT_BIG (*) AS Expr1 FROM dbo.Payments WHERE (Voided = 0) GROUP BY CONVERT(smalldatetime, DATEDIFF([DAY], CONVERT(DATETIME, '1900-01-01 00:00:00', 102), PmtDate), 101) Pretty darn ugly, if I may say so. I like your method better. Thanks again. -- John [quoted text, click to view] "Dan Guzman" wrote: > It looks like you are using SQL 2000. > > Erland posted one method that will work in SQL 2000. Here's an extention of > that technique that will return a smalldatetime: > > CONVERT(smalldatetime, CONVERT(char(8), PmtDate, 112), 112) AS PmtDate > > -- > Hope this helps. > > Dan Guzman > SQL Server MVP > > "JT" <Jthayer@online.nospam> wrote in message > news:11FDCEC3-F22E-4572-B211-AF822FCCC5AC@microsoft.com... > > Thanks Dan, > > From BOL: > > CONVERT: Deterministic unless used with datetime, smalldatetime, or > > sql_variant. The datetime and smalldatetime data types are deterministic > > if > > the style parameter is also specified. > > In theory, it would sure seem that your solution should work. In > > practice, > > I get the same error. Any other thoughts? > > -- > > John > > > > > > "Dan Guzman" wrote: > > > >> > Is there another way to cast PmtDate > >> > that will allow me to do the grouping and aggregation I am trying to > >> > achieve? > >> > >> CAST is non-deterministic when used with smalldatetime. Try CONVERT with > >> a > >> style parameter instead: > >> > >> CONVERT(smalldatetime, DATEDIFF(DAY, 0, PmtDate), 112) > >> > >> -- > >> Hope this helps. > >> > >> Dan Guzman > >> SQL Server MVP > >> > >> "JT" <Jthayer@online.nospam> wrote in message > >> news:2DA1D643-75AC-4B61-AE2C-E08C3085F5A7@microsoft.com... > >> > Hi all, > >> > I am trying to create an indexed view to do aggregation on a table of > >> > Payments. The table has columns as follows: > >> > > >> > CREATE TABLE [Payments] ( > >> > [PmtKey] [int] IDENTITY (1, 1) NOT NULL , > >> > [PmtAmt] [smallmoney] NOT NULL , > >> > [PmtDate] [smalldatetime] NOT NULL , > >> > [Voided] [bit] NOT NULL CONSTRAINT [DF_Payments_Voided] DEFAULT (0), > >> > CONSTRAINT [PK_Payments] PRIMARY KEY CLUSTERED > >> > ( > >> > [PmtKey] > >> > ) ON [PRIMARY] > >> > ) ON [PRIMARY] > >> > > >> > I am trying to create an indexed view as follows: > >> > > >> > CREATE VIEW dbo.vwPayments_ByDate > >> > WITH SCHEMABINDING > >> > AS > >> > SELECT > >> > CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, > >> > SUM(PmtAmt) AS DaysPmts, > >> > COUNT_BIG (*) AS Expr1 > >> > > >> > FROM dbo.Payments > >> > WHERE (Voided = 0) > >> > GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) > >> > > >> > I am doing the cast to try to get all payments grouped by the same > >> > date, > >> > ignoring the time portion. > >> > When I go to add a unique clustered index to this view, > >> > > >> > CREATE UNIQUE CLUSTERED > >> > INDEX [PK_vwPmts_ByDate] ON [dbo].[vwPayments_ByDate] ([PmtDate]) > >> > WITH > >> > FILLFACTOR = 85 > >> > > >> > I am told that the column PmtDate is non-detereministic or too > >> > imprecise. > >> > I understand the requirement that the indices in an indexed view cannot > >> > be > >> > nullable and must be deterministic. Is there another way to cast > >> > PmtDate > >> > that will allow me to do the grouping and aggregation I am trying to > >> > achieve? > >> > > >> > Thanks. > >> > -- > >> > John > >> > >> > >> > >
On second thought, I think I will stick with my convoluted method as it preserves the column as smalldatetime datatype, which will be helpful in sorting records for reporting. Sorting dates cast as Char(8) gives you all of the January's, then the February's when converted to style 101, which is what I use in my reports. Thanks again. -- John [quoted text, click to view] "Erland Sommarskog" wrote: > JT (Jthayer@online.nospam) writes: > > I am trying to create an indexed view as follows: > > > > CREATE VIEW dbo.vwPayments_ByDate > > WITH SCHEMABINDING > > AS > > SELECT > > CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, > > SUM(PmtAmt) AS DaysPmts, > > COUNT_BIG (*) AS Expr1 > > > > FROM dbo.Payments > > WHERE (Voided = 0) > > GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) > > Dan posted a solution, but it works only on SQL 2005. (I've tested). > > On SQL 2000 you may have to let it suffice with: > > CREATE VIEW dbo.vwPayments_ByDate > WITH SCHEMABINDING > AS > SELECT CONVERT(char(8), PmtDate, 112) AS PmtDate, > SUM(PmtAmt) AS DaysPmts, > COUNT_BIG (*) AS Expr1 > FROM dbo.Payments > WHERE (Voided = 0) > GROUP BY CONVERT(char(8), PmtDate, 112) > > Thus, you get PmtDate as a char(8) column instead. > > > > -- > Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se > > Books Online for SQL Server 2005 at > http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx > Books Online for SQL Server 2000 at > http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx
JT (Jthayer@online.nospam) writes: [quoted text, click to view] > I am trying to create an indexed view as follows: > > CREATE VIEW dbo.vwPayments_ByDate > WITH SCHEMABINDING > AS > SELECT > CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME) AS PmtDate, > SUM(PmtAmt) AS DaysPmts, > COUNT_BIG (*) AS Expr1 > > FROM dbo.Payments > WHERE (Voided = 0) > GROUP BY CAST(DATEDIFF(DAY,0,PmtDate) AS SMALLDATETIME)
Dan posted a solution, but it works only on SQL 2005. (I've tested). On SQL 2000 you may have to let it suffice with: CREATE VIEW dbo.vwPayments_ByDate WITH SCHEMABINDING AS SELECT CONVERT(char(8), PmtDate, 112) AS PmtDate, SUM(PmtAmt) AS DaysPmts, COUNT_BIG (*) AS Expr1 FROM dbo.Payments WHERE (Voided = 0) GROUP BY CONVERT(char(8), PmtDate, 112) Thus, you get PmtDate as a char(8) column instead. -- Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se Books Online for SQL Server 2005 at http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx Books Online for SQL Server 2000 at
Let's start with everything is wrong. You have an IDENTITY column, no key, and use assembly language style BIT flags and proprietary MONEY data types in spite of the math errors in it. The payments are not posted to an account or an invoice? Wild guess at a valid design CREATE TABLE Payments (invoice_nbr INTEGER NOT NULL, payment_nbr INTEGER NOT NULL, PRIMARY KEY (invoice_nbr, payment_nbr), pmt_amt DECIMAL (12,4) NOT NULL, pmt_date DATETIME NOT NULL CHECK (pmt_date = CAST (FLOOR(CAST(pmt_date AS FLOAT)) AS DATETIME)), -- other ways to do this, too pmt_status INTEGER NOT NULL); [quoted text, click to view] >> I am doing the cast to try to get all payments grouped by the same date, ignoring the time portion. <<
What if you had a relational approach and not allow bad data that has to be clean out later? Good DDL will save you from complex kludges.
Thanks for the enlightenment! You forgot the Volkswagen lecture, as the view is named vw... The actual table is considerably different than the simplified example I posted. Seriously, though, thanks for your input, especially about the datetime column. Something to consider... -- John [quoted text, click to view] "--CELKO--" wrote: > Let's start with everything is wrong. You have an IDENTITY column, no > key, and use assembly language style BIT flags and proprietary MONEY > data types in spite of the math errors in it. The payments are not > posted to an account or an invoice? Wild guess at a valid design > > CREATE TABLE Payments > (invoice_nbr INTEGER NOT NULL, > payment_nbr INTEGER NOT NULL, > PRIMARY KEY (invoice_nbr, payment_nbr), > pmt_amt DECIMAL (12,4) NOT NULL, > pmt_date DATETIME NOT NULL > CHECK (pmt_date = CAST (FLOOR(CAST(pmt_date AS FLOAT)) AS > DATETIME)), -- other ways to do this, too > pmt_status INTEGER NOT NULL); > > >> I am doing the cast to try to get all payments grouped by the same date, ignoring the time portion. << > > What if you had a relational approach and not allow bad data that has > to be clean out later? Good DDL will save you from complex kludges. >
I pikced up a slogan from Graeme Simsion, who is a data quality and design guru -- "Mop the floor, but then fix the leak!" . I am getting a presentation on advanced DDL ready for PASS this year. DML gets all the glory, but good DDL does the real work. And one day, I will figure out DCL trick. s
Don't see what you're looking for? Try a search.
|