I have a table with data. Table was created by this code:
create table [tmp].[Test]
(
[RecordId] bigint not null
,[DateId] int not null
,[CustomerId] int not null
);
alter table [tmp].[Test]
add constraint [PK_REP_51671] primary key ([RecordId])
I have partition function and partition scheme:
CREATE PARTITION FUNCTION PartitionByYear_function(int)
AS RANGE RIGHT
FOR VALUES(
20130101
,20140101
,20150101
,20160101
,20170101
,20180101
,20190101
,20200101
,20210101
,20220101
,20230101
,20240101
,20250101
,20260101
,20270101
,20280101
,20290101
,20300101
,20310101
,20320101
,20330101
,20340101
,20350101
,20360101
,20370101
,20380101
,20390101
,20400101
,20410101
,20420101
,20430101
,20440101
,20450101
,20460101
,20470101
,20480101
,20490101
,20500101
,20510101
,20520101
,20530101
,20540101
,20550101
,20560101
,20570101
,20580101
,20590101
,20600101
);
GO
CREATE PARTITION SCHEME PartitionByYear_Scheme
AS PARTITION PartitionByYear_function
ALL TO ([PRIMARY])
GO
But I don't know how to add partitions to table Test and how to enable Incremental Update Statistics by alter. I know how to add this things to new table by create but how can I add parttitions and statistics to existing table with data by alter?
You have everything prepared. You should recreate your table using the partition schema:
create table [tmp].[Test]
(
[RecordId] bigint not null
,[DateId] int not null
,[CustomerId] int not null
)on PartitionByYear_Scheme([DateId]);
Related
I want to have a table with this properties:
CREATE TABLE status
(
identificationnumber BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
desc varchar(10)
);
Suddenly the production table was already created and has a enormous amount of data. Schema that is already in use:
CREATE TABLE status
(
identificationnumber BIGINT NOT NULL PRIMARY KEY,
desc varchar(10)
);
Is it possible to update the schema with an autoincrement?
Technically it is possible, but may depend on the size of data. You can check it by yourself at TEST/QAS system and then apply the change to production.
Here's the code I used:
/*Create example table*/
create column table tst_tab (
x int
);
/*Fill it with some data*/
insert into tst_tab
select 1 from dummy union all
select 2 from dummy union all
select 3 from dummy
;
/*Add identity column*/
alter table tst_tab
add(id int generated by default as identity);
/*Statement 'alter table tst_tab add(id int generated by default as identity)'
successfully executed in 14 ms 281 µs*/
/*Check results*/
select * from tst_tab;
Please see the issue below. Any help would be appreciated. The same procedure worked fine on a similar database using the same partition function definition. The partitioned table is identical to the staging table except that the staging table contains constraints.
CREATE PARTITION FUNCTION [CO_CODE_RANGE](nvarchar(255)) AS RANGE RIGHT FOR VALUES (N'00001', N'00005', N'00009', N'00012', N'000136', N'00015', N'00016', N'00020', N'00021', N'00025', N'00026', N'00027', N'00028', N'00030', N'00031', N'00032', N'00035', N'00040', N'00045', N'00050', N'00055', N'00056', N'00057', N'00058', N'00059', N'00060', N'00061', N'00062', N'00063', N'00064', N'00065', N'00066', N'00067', N'00069', N'00070', N'00073', N'00075', N'00076', N'00077', N'00079', N'00081', N'00083', N'00084', N'00085', N'00087', N'00089', N'00096', N'00097', N'00104', N'00105', N'00151', N'00170', N'00350', N'00G82', N'00N82', N'00S82', N'00SW2', N'14086', N'14088', N'20350', N'30350', N'40350', N'50350')
select top 0 * into FDM.F_GL_PREM_SP from FDM.F_GL_PREM
CREATE CLUSTERED COLUMNSTORE INDEX cx_cs_F_GL_PREM_SP
ON FDM.F_GL_PREM_SP WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0)
ALTER TABLE FDM.F_GL_PREM SWITCH PARTITION 58 TO FDM.F_GL_PREM_SP
select distinct ETL_SRC_CO_CODE from FDM.F_GL_PREM_SP
00SW2
ALTER TABLE FDM.F_GL_PREM_SP WITH CHECK
ADD CONSTRAINT CK_F_GL_PREM_SP CHECK (([ETL_SRC_CO_CODE]=('00SW2')))
ALTER TABLE FDM.F_GL_PREM_SP WITH CHECK
ADD CONSTRAINT CK_F_GL_PREM_SP2 CHECK (([ETL_SRC_CO_CODE] is not null))
ALTER TABLE FDM.F_GL_PREM_SP
SWITCH TO FDM.F_GL_PREM PARTITION 58
Msg 4982, Level 16, State 1, Line 41 ALTER TABLE SWITCH statement
failed. Check constraints of source table
'FDW_FDM.FDM.F_GL_PREM_SP' allow values that are not allowed by
range defined by partition 58 on target table
'FDW_FDM.FDM.F_GL_PREM'.
TEST Data:
Create table dbo.part_test (ETL_SRC_CO_CODE nvarchar(255) NOT NULL, PART_ID int NOT NULL) ON [CO_CODE_RANGE_SCHEME]([ETL_SRC_CO_CODE])
CREATE CLUSTERED COLUMNSTORE INDEX [cx_cs_part_test] ON part_test WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0) on [CO_CODE_RANGE_SCHEME]([ETL_SRC_CO_CODE])
insert into dbo.part_test values ('00059', 1);
insert into dbo.part_test values ('00089', 2);
insert into dbo.part_test values ('00350', 3);
select top 0* into dbo.part_test_s from dbo.part_test
CREATE CLUSTERED COLUMNSTORE INDEX [cx_cs_part_test_s] ON part_test_s WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0)
alter table part_test switch partition 54 to part_test_s
ALTER TABLE part_test_s WITH CHECK ADD CONSTRAINT CK_PART_TEST_S CHECK (([ETL_SRC_CO_CODE]=('00350')))
ALTER TABLE part_test_s WITH CHECK ADD CONSTRAINT CK_PART_TEST_S2 CHECK (([ETL_SRC_CO_CODE] is not null))
alter table part_test_s switch to part_test partition 54
I'm using database first approach with EF core and trying to figure out a clean solution to the below problem -
Consider a Student attendance table (irrelevant columns removed) below that stores date of class and allows the student to enter his class rating -
create table Student (
Id int Identity(1, 1) not null,
ClassDate smalldatetime not null,
ClassRatingByStudent varchar(250) not null
)
This is a webapp where school attendance system automatically populates the above table at EOD and then the student (let's say a few days later) is required to add class ratings. When the table is populated by the school attendance system, there is nothing in the ClassRatingByStudent column. Then when the student logs in, he must add the rating.
As you see, ClassRatingByStudent must be null when the school attendance system populates the table and must be not-null when the student saves his changes. One obvious solution is make ClassRatingByStudent column nullable ad handle it in the code but I'm wondering if there is a neater database (or maybe EF) level solution exists or some sort of pattern/architecture guidelines for this type of scenarios?
I don't know but maybe CHECK constraint could help you:
CREATE TABLE TestTable(
ID int NOT NULL IDENTITY,
RatingAllowed bit NOT NULL DEFAULT 0, -- switcher
RatingValue varchar(250),
CONSTRAINT PK_TestTable PRIMARY KEY(ID),
CONSTRAINT CK_TestTable_RatingValue CHECK( -- constraint
CASE
WHEN RatingAllowed=0 AND RatingValue IS NULL THEN 1
WHEN RatingAllowed=1 AND RatingValue IS NOT NULL THEN 1
ELSE 0
END=1
)
)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,NULL)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,'AAA')
-- The INSERT statement conflicted with the CHECK constraint "CK_TestTable_RatingValue"
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,'AAA')
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,NULL)
I found a variant how to check using another table as switcher
CREATE TABLE TableA(
ID int NOT NULL IDENTITY PRIMARY KEY,
StudentID int NOT NULL,
Grade int
)
CREATE TABLE TableB(
StudentID int NOT NULL PRIMARY KEY
)
GO
-- auxiliary function
CREATE FUNCTION GradeIsAllowed(#StudentID int)
RETURNS bit
BEGIN
DECLARE #Result bit=CASE WHEN EXISTS(SELECT * FROM TableB WHERE StudentID=#StudentID) THEN 1 ELSE 0 END
RETURN #Result
END
GO
-- constraint to check
ALTER TABLE TableA ADD CONSTRAINT CK_TableA_Grade CHECK(
CASE dbo.GradeIsAllowed(StudentID) -- then we can use the function here
WHEN 1 THEN CASE WHEN Grade IS NOT NULL THEN 1 ELSE 0 END
WHEN 0 THEN CASE WHEN Grade IS NULL THEN 1 ELSE 0 END
END=1)
GO
-- Tests
INSERT TableB(StudentID)VALUES(2) -- allowed student
INSERT TableA(StudentID,Grade)VALUES(1,NULL) -- OK
INSERT TableA(StudentID,Grade)VALUES(2,5) -- OK
INSERT TableA(StudentID,Grade)VALUES(1,4) -- Error
INSERT TableA(StudentID,Grade)VALUES(2,NULL) -- Error
INSERT TableB(StudentID)VALUES(1) -- add 1
UPDATE TableA SET Grade=4 WHERE StudentID=1 -- OK
UPDATE TableA SET Grade=NULL WHERE StudentID=1 -- Error
I want not to allow my DB user to enter bigger dates than 2017-03-18. How can add this constraint to my table?
Is this Correct?
(Year([ContractEnd])<2017) and (Month([ContractEnd])<03) and (Day([ContractEnd])<18)
You can add a constraint like that to an existing table like so:
alter table t add constraint chk_ContractEnd_lt_20170319
check (ContractEnd<'20170319');
rextester demo: http://rextester.com/FQWFMI88817
create table t (
id int not null identity(1,1)
, ContractEnd date
/* at table creation */
, constraint chk_ContractEnd_lt_20170319 check (ContractEnd<'20170319')
)
alter table t drop constraint chk_ContractEnd_lt_20170319;
/* to existing table */
alter table t add constraint chk_ContractEnd_lt_20170319
check (ContractEnd<='20170318');
insert into t values ('20161231')
insert into t values ('20170318')
/* all good */
insert into t values ('20170319')
/* -- Error, constraint violation */
Try
[ContractEnd] DATE CHECK ([ContractEnd] <= '20170318')
I have a table like this :
create table ReceptionR1
(
numOrdre char(20) not null,
dateDepot datetime null,
...
)
I want to increment my id field (numOrdre) like '225/2015','226/2015',...,'1/2016' etc. What should I have to do for that?
2015 means the actual year.
Please let me know any possible way.
You really, and I mean Really don't want to do such a thing, especially as your primary key. You better use a simple int identity column for you primary key and add a non nullable create date column of type datetime2 with a default value of sysDateTime().
Create the increment number by year either as a calculated column or by using an instead of insert trigger (if you don't want it to be re-calculated each time). This can be done fairly easy with the use of row_number function.
As everyone else has said - don't use this as your primary key! But you could do the following, if you're on SQL Server 2012 or newer:
-- step 1 - create a sequence
CREATE SEQUENCE dbo.SeqOrderNo AS INT
START WITH 1001 -- start with whatever value you need
INCREMENT BY 1
NO CYCLE
NO CACHE;
-- create your table - use INT IDENTITY as your primary key
CREATE TABLE dbo.ReceptionR1
(
ID INT IDENTITY
CONSTRAINT PK_ReceptionR1 PRIMARY KEY CLUSTERED,
dateDepot DATE NOT NULL,
...
-- add a colum called "SeqNumber" that gets filled from the sequence
SeqNumber INT,
-- you can add a *computed* column here
OrderNo = CAST(YEAR(dateDepot) AS VARCHAR(4)) + '/' + CAST(SeqNumber AS VARCHAR(4))
)
So now, when you insert a row, it has a proper and well defined primary key (ID), and when you fill the SeqNumber with
INSERT INTO dbo.ReceptionR1 (dateDepot, SeqNumber)
VALUES (SYSDATETIME(), NEXT VALUE FOR dbo.SeqOrderNo)
then the SeqNumber column gets the next value for the sequence, and the OrderNo computed column gets filled with 2015/1001, 2015/1002 and so forth.
Now when 2016 comes around, you just reset the sequence back to a starting value:
ALTER SEQUENCE dbo.SeqOrderNo RESTART WITH 1000;
and you're done - the rest of your solution works as before.
If you want to make sure you never accidentally insert a duplicate value, you can even put a unique index on your OrderNo column in your table.
Once more, you cannot use the combo field as your primary key. This solution sort or works on earlier versions of SQL and calculates the new annual YearlySeq counter automatically - but you had better have an index on dateDepot and you might still have issues if there are many, many (100's of thousands) of rows per year.
In short: fight the requirement.
Given
create table dbo.ReceptionR1
(
ReceptionR1ID INT IDENTITY PRIMARY KEY,
YearlySeq INT ,
dateDepot datetime DEFAULT (GETDATE()) ,
somethingElse varchar(99) null,
numOrdre as LTRIM(STR(YearlySeq)) + '/' + CONVERT(CHAR(4),dateDepot,111)
)
GO
CREATE TRIGGER R1Insert on dbo.ReceptionR1 for INSERT
as
UPDATE tt SET YearlySeq = ISNULL(ii.ReceptionR1ID - (SELECT MIN(ReceptionR1ID) FROM dbo.ReceptionR1 xr WHERE DATEPART(year,xr.dateDepot) = DATEPART(year,ii.dateDepot) and xr.ReceptionR1ID <> ii.ReceptionR1ID ),0) + 1
FROM dbo.ReceptionR1 tt
JOIN inserted ii on ii.ReceptionR1ID = tt.ReceptionR1ID
GO
insert into ReceptionR1 (somethingElse) values ('dumb')
insert into ReceptionR1 (somethingElse) values ('requirements')
insert into ReceptionR1 (somethingElse) values ('lead')
insert into ReceptionR1 (somethingElse) values ('to')
insert into ReceptionR1 (somethingElse) values ('big')
insert into ReceptionR1 (somethingElse) values ('problems')
insert into ReceptionR1 (somethingElse) values ('later')
select * from ReceptionR1