MySQL unique clustered constraint not constraining as expected - sql

I'm creating a table with:
CREATE TABLE movies
(
id INT AUTO_INCREMENT PRIMARY KEY,
name CHAR(255) NOT NULL,
year INT NOT NULL,
inyear CHAR(10),
CONSTRAINT UNIQUE CLUSTERED (name, year, inyear)
);
(this is jdbc SQL)
Which creates a MySQL table with a clustered index, "index kind" is "unique", and spans the three clustered columns:
mysql screen http://img510.imageshack.us/img510/930/mysqlscreenshot.th.jpg
full size
However, once I dump my data (without exceptions thrown), I see that the uniqueness constraint has failed:
SELECT * FROM movies
WHERE name = 'Flawless' AND year = 2007 AND inyear IS NULL;
gives:
id, name, year, inyear
162169, 'Flawless', 2007, NULL
162170, 'Flawless', 2007, NULL
Does anyone know what I'm doing wrong here?

MySQL does not consider NULL values as equal; hence, why the unique constraint appears to not be working. To get around this, you can add a computed column to the table which is defined as:
nullCatch as (case when inyear is null then '-1' else inyear)
Substitute this column in for 'inyear' in the constraint:
CONSTRAINT UNIQUE CLUSTERED (name, year, nullCatch)

Related

Suggested Indexing for table with 50 million rows is queried using its CREATED_DATE column and USER_TYPE column

Table Users:
ID PK INT
USER_TYPE VARCHAR(50) NOT NULL
CREATED_DATE DATETIME2(7) NOT NULL
I have this table with 50 million rows, and it is queries using the following where clause:
WHERE
u.USER_TYPE= 'manager'
AND u.CREATED_DATE >= #StartDate
AND u.CREATED_DATE < #EndDate
What would be a good starting point for an index on this table to optimize for the above query where clause?
For that query, the index you want is a composite index with two columns: (user_type, created_date). The order matters, you want user_type first because of the equality comparison.
You'll be well served by creating a table with user types having an arbitrary INT ID and referring to the manager type by ID, instead of having the manager type directly in the users table. This will narrow the table data as well as any index referring to the user type.
CREATE TABLE user_type (
id INT NOT NULL IDENTITY(1,1),
description NVARCHAR(128) NOT NULL,
CONSTRAINT pk_user_type PRIMARY KEY CLUSTERED(id)
);
CREATE TABLE users (
id INT NOT NULL IDENTITY(1,1),
user_type_id INT NOT NULL,
created_date DATETIME2(7) NOT NULL,
CONSTRAINT pk_users PRIMARY KEY CLUSTERED(id),
CONSTRAINT fk_users_user_type FOREIGN KEY(user_type_id) REFERENCES user_type(id)
);
CREATE NONCLUSTERED INDEX
ix_users_type_created
ON
users (
user_type_id,
created_date
);
You would be querying using the user_type ID rather than directly with the text of course.
For any query. Run the query in SSMS with "Include Actual Execution Plan" on. SSMS will advice an index if it feels proper index doesn't exist.

Why Postgresql doesn't allow grouping sets in INSERT SELECT queries?

The issue here is simple as that, Postgresql doesn't allow the following query structure:
-- TABLE OF FACTS
CREATE TABLE facts_table (
id integer NOT NULL,
description CHARACTER VARYING(50),
amount NUMERIC(12,2) DEFAULT 0,
quantity INTEGER,
detail_1 CHARACTER VARYING(50),
detail_2 CHARACTER VARYING(50),
detail_3 CHARACTER VARYING(50),
time TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT LOCALTIMESTAMP(0)
);
ALTER TABLE facts_table ADD PRIMARY KEY(id);
-- SUMMARIZED TABLE
CREATE TABLE table_cube (
id INTEGER,
description CHARACTER VARYING(50),
amount NUMERIC(12,2) DEFAULT 0,
quantity INTEGER,
time TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT LOCALTIMESTAMP(0)
);
ALTER TABLE table_cube ADD PRIMARY KEY(id);
INSERT INTO table_cube(id, description, amount, quantity, time)
SELECT
id,
description,
SUM(amount) AS amount,
SUM(quantity) AS quantity,
time
FROM facts_table
GROUP BY CUBE(id, description, time);
----------------------------------------------------------------
ERROR: grouping sets are not allowed in INSERT SELECT queries.
I think it's pretty obvious that CUBE produces null results on every field indicated as a grouping set (as it computes every possible combination), therefore I can not insert that row in my table_cube table, so , does Postgres just assume, that I'm trying to insert a row in a table with a PK field? Even if the table_cube table doesn't have a PK, this cannot be accomplished.
Thanks.
Version: PostgreSQL 9.6
You have define table_cube(id) as Primary Key. So, If Cube contains null
values, it can't be inserted. I have checked without having id as Primary
Key, It works fine and when define id as primary key I got error:
"ERROR:id contains null values" SQL state: 23502
As suggested by Haleemur Ali,
"If a constraint is required, use a unique index with all the grouping
set columns: CREATE UNIQUE INDEX unq_table_cube_id_description_time ON
table_cube(id, description, time); Please update your question with more
information on database & version."
is a good option. But you have to remove Primary Key On "Id" and assign only Unique Key as suggested above as with having primary key and unique key again get this error:
ERROR: null value in column "id" violates not-null constraint
DETAIL: Failing row contains (null, null, 1300, 1522, null).
SQL state: 23502
So, the conclusion is, with unique index there is no need of Primary Key or with cube there is no need of unique index or Primary Key.

Check if a value appears only once in a column

I want to create a table for managing versions of parameters...
In this table there is a column of type char that lets me know what version I have to use :
create table PARAMETERS_VERSION (
ID number not null,
VERSION number not null,
DATE_START date not null,
DATE_END date check(DATE_START <= DATE_END) not null
ISUSED char(1) check(ISUSED in ('Y','N')) not null,
constraint PARAMETERS_VERSION_VERSION_PK primary key (ID),
constraint PARAMETERS_VERSION_VERSION_UK unique (ISUSED)
);
How to define a unique constraint on the column ISUSED to have only a single row with the value 'Y' (and the others with 'N') ?
By the way, is my check constraint on DATE_END is correct ?
Oracle doesn't quite support partial or filtered indexes. Instead, you can use a functional index with some cleverness:
create unique index idx_parametersversion_isused
on parameters_version(case when is_used = 'Y' then -1 else id end);
That is, when is_used has any value other than Y, then the primary key is used. When it is Y, then a constant is used, so two values will conflict.

Can't serialize transient record type postgres

I am trying to make my calculation dynamic based on certain criteria as below, but when I try to send the fields dynamically in to my calculation logic, it fails with the error " Can't serialize transient record type":
Create table statement :
create table calculation_t(
Id serial,
product_id integer not null,
metric_id integer not null,
start_date date,
end_date date,
calculation_logic varchar(50),
insert_timestamp timestamp default current_timestamp,
CONSTRAINT calculation_pk PRIMARY KEY(Id),
CONSTRAINT calculation_pid_fk FOREIGN KEY(product_id) REFERENCES Product_T(Product_id),
CONSTRAINT calc_mid_fk FOREIGN KEY(metric_id) REFERENCES metric_T(metric_id)
);
Insert statement :
insert into calculation_t(product_id,metric_id,calculation_logic)
select a.product_id,b.metric_id,
(case when b.metric_id=2 then
('$1-$2') else
'$1/$2' end) calc
from product_t a,metric_t b
Select statement which throws the mentioned error :
select *,(1,2,calculation_logic) from calculation_t
Note : I am using Greenplum database.
Try to remove parenthesis form your query:
select *,1,2,calculation_logic from calculation_t
It worked for me.
Thanx,

Primary key consists of a foreign key and a identity and should reset identity under a condition

create table Linq_TB
{
url_id int NOTNULL,
Pg_Name nvarchar(50) NOTNULL,
URL nvarchar(50) NUTNULL,
CONSTRAINT Linq_id PRIMARY KEY (url_id,DBCC Checkident(Linq_TB,RESEED,0) case url_id not in(select URL_Id from URL_TB ))
}
I want to make a table which it's primary key is Linq_id and gets it's value from both the url_id and identity with start from 1 and increments 1 by 1. url_id is a foreign key. For example if url_id is 1, linq_id's will be 11, 12, 13,... and I also want to reset linq_id identity when the url_id changes.
What should the query be? The query above doesn't work, why?
Thanks in advance
Well, a constraint contains conditions and not code to be executed. You should consider using a stored procedure for your task and also a homegrown method of assigning IDs.
However, it is not a common practice to have your primary keys 'pretty' or formatted, as there is no real benefit (except maybe for debugging purposes maybe).
I do not recommend executing DBCC whenever your url_ID changes. This has a great negative impact on performance.
Why don't you leave the IDs like they are?
You can do this with the following table and trigger definitions:
CREATE TABLE Linq_TB
(
url_id INT NOT NULL,
Linq_id INT NOT NULL,
Pg_Name NVARCHAR(50) NOT NULL,
URL NVARCHAR(50) NOT NULL,
CONSTRAINT PK_Link_TB PRIMARY KEY (url_id, Linq_id),
CONSTRAINT FK_URL_TB_URL_ID FOREIGN KEY (url_id) REFERENCES URL_TB (url_id)
)
GO
CREATE TRIGGER tr_Linq_TB_InsertUpdate
ON Linq_TB
INSTEAD OF INSERT
AS
INSERT INTO Linq_TB
SELECT i.url_id,
ISNULL(tb.Linq_id, 0)
+ row_number() over (partition by i.url_id order by (select 1)),
i.Pg_Name, i.URL
FROM inserted i
LEFT OUTER JOIN
(
SELECT url_id, MAX(Linq_ID) Linq_id
FROM Linq_TB
GROUP BY url_id
) tb ON i.url_id = tb.url_id
GO
The CREATE TABLE defines your columns and constraints. And, the trigger creates the logic to generate a sequence value in your Linq_id column for each url_id.
Note that the logic in the trigger is not complete. A couple of issues are not addressed: 1) If the url_id changes for a row, the trigger doesn't update the Link_id, and 2) deleting rows will lead to gaps in the Linq_TB column sequence.