How to set a constraint on a group of values? - sqlite

I already have an id as primary key so I can't use this construct.
I have a table with 5 fields, I'd like to not have more than one row with the same values of field1 field2 and field3.
That is, suppose I have A,B,C,D,E as field values (+1 id column)
Rows like;
1 2 3 4 5
A B C F A (row1)
A B E F B (row 2)
are allowed as field 3 is different among rows (C in row1 and E in row 2).
But a row
A B C E B (row 3)
should not be allowed, as field 1 2 and 3 are exactly the same of row 1.
primary key(field1,field2,field3) would solve my problem, but I'd like for it to be an id and so I can't use it.

There are more constraint types than PRIMARY KEY.
Use a UNIQUE constraint:
CREATE TABLE MyTable(
ID PRIMARY KEY,
Field1,
Field2,
Field3,
[...],
UNIQUE (Field1, Field2, Field3)
);

Related

How to assign a 0 for count if the value doesnt exist in the table

I have a table of ratings
|EMPLOYEE|Rating|
1 B
2 B
3 C
4 NULL
5 NULL
6 NULL
and i want to retrieve the count of the grades by each grading like so
Result set
|Rating|Count|
A 0
B 2
C 1
D 0
E 0
I used this query but the grades that isnt in the table will jsut appear as null
select rating,count(rating) from table group by rating
I also used this query which is basically a pivot of the above result set but for some reason it shows 3 rows of repeating data instead of just 1
select (select count(rating) from table where rating = 'E'),(select count(rating) from table where rating = 'D'),(select count(rating) from table where rating = 'C'),(select count(rating) from table where rating = 'B'),(select count(rating) from table where rating = 'A') from table group by rating
If you had a table for the assignable ratings then it would be quite simple (and flexible)
e.g. consider :-
Your existing table.
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (employee TEXT, rating text);
INSERT INTO mytable VALUES (1,'B'),(2,'B'),(3,'C'),(4,null),(5,null),(6,null);
The rating table.
DROP TABLE IF EXISTS rating;
CREATE TABLE IF NOT EXISTS rating (rating);
INSERT INTO rating VALUES('A'),('B'),('C'),('D'),('E');
Then :-
SELECT rating.rating, (SELECT count(*) FROM mytable WHERE rating.rating = mytable.rating) FROM rating;
Results in :-
Flexibility
Add some new ratings e.g. as per :-
INSERT INTO rating VALUES('X'),('Y'),('Z');
And then run:--
SELECT rating.rating, (SELECT count(*) FROM mytable WHERE rating.rating = mytable.rating) FROM rating;
results in :-

SQLITE3 - Deleting rows that have multiple columns of the same value

I have an SQLite3 database from which I want to remove rows that have two fields of the same value.
It seems that I am able to select such values with this query:
SELECT * FROM mydb GROUP BY user_id, num HAVING COUNT(*) > 1
However I am not able to delete them.
DELETE FROM mydb WHERE user_id IN (SELECT * FROM mydb GROUP BY user_id, num HAVING COUNT(*) > 1)
returns a syntax error.
This is what I expect:
Example:
id user_id num
1 1 1
2 1 1
3 2 1
4 1 2
5 2 2
In this example id 1 and 2 have both columns (user_id and num) of the same value so they should be removed. Preferably, but not necessarily I would like to have a solution that would leave only one such row (doesn't matter which one).
Result:
id user_id num
2 1 1
3 2 1
4 1 2
5 2 2
Note: id is a primary key. user_id is a foreign key. num is an INTEGER.
You were having a syntax error because your IN operator has a single value on the left (user_id) but a table of non-single-value rows in the right side (SELECT *). Compare like with like; WHERE user_id IN (SELECT user_id ...) to avoid it.
Anyway, here's a query to delete all-but-newest:
DELETE FROM mydb
WHERE id NOT IN (
SELECT MAX(id) FROM mydb
GROUP BY user_id, num
);
The subquery will return the highest id for every unique (user_id, num) combination. Then we just delete all the other rows. I.e. in your example, the subquery would return 2, 3, 4, 5 as "correct", which would result in deletion of row 1.

Unique Index on two columns and vice versa

I have the following table in postgres 9.5:
CREATE TABLE public.test
(
id bigint NOT NULL DEFAULT nextval('test_id_seq'::regclass),
id1 integer,
id2 integer,
CONSTRAINT test_pkey PRIMARY KEY (id)
);
I want to add restrictions on both columns which only allows recordsets where
the new recordset (id1,id2) is not present and
the new recordset (id1,id2) is not present as (id2,id1) and
id1 and id2 of new recordset are not equal
It should lool like this:
id | id1 | id2
---------------
1 | 1 | 1 <-- invalid (violates restriction 3.)
2 | 1 | 2 <-- valid
3 | 1 | 2 <-- invalid (violates restriction 1.)
4 | 2 | 1 <-- invalid (violates restriction 2.)
5 | 3 | 1 <-- valid
6 | 3 | 2 <-- valid
For restriction 1, I have added:
ALTER TABLE test ADD CONSTRAINT test_id1_id2_unique UNIQUE(id1, id2);
But how to add constraints for 2. and 3.?
Final solution with help of a_horse_with_no_name:
CREATE TABLE public.test(
id bigint NOT NULL DEFAULT nextval('test_id_seq'::regclass),
id1 integer NOT NULL,
id2 integer NOT NULL,
CONSTRAINT test_pkey PRIMARY KEY (id),
CONSTRAINT test_check CHECK (id1 <> id2)
);
CREATE UNIQUE INDEX test_id1_id2_unique
ON public.test
USING btree
((LEAST(id1, id2)), (GREATEST(id1, id2)));
You can create a unique index to cover both 1. and 2.
create unique index on test ( least(id1,id2), greatest(id1,id2) );
For 3. you need a check constraint:
CREATE TABLE public.test
(
id bigint NOT NULL DEFAULT nextval('test_id_seq'::regclass),
id1 integer,
id2 integer,
constraint check_not_equal check (id1 is distinct from id2),
CONSTRAINT test_pkey PRIMARY KEY (id)
);
You probably want both ids to be NOT NULL as well. In that case you could also use check (id1 <> id2)

Sqlite how to select case for multiple values in a column

So, I have this table:
id|otherid|key|value
--------------------
1 1 ak av
2 1 bk bv
3 2 ak av
3 2 ak av2
The things to note is that other ids are repeating and they can have same keys with values multiple times. The thing I want to retrieve would be the value for the key, or, if there are multiple values for same key some string.
So, I'd like to receive for otherids
otherid|key|value
-----------------
1 ak av
1 bk bv
2 ak SEQUENCE
Where 'SEQUENCE' string allows me to know that there are multiple values for the single key for otherid. What query would accomplish this?
To get one output row for multiple input rows, use grouping.
The count of rows in the group is available with COUNT(*); you can handle the cases with a CASE expression:
SELECT otherid,
key,
CASE COUNT(*)
WHEN 1 THEN MIN(value)
ELSE 'SEQUENCE'
END AS value
FROM MyTable
GROUP BY otherid,
key;
SELECT DISTINCT
otherid,key,
(SELECT
CASE
WHEN COUNT(value)=1 THEN value
WHEN COUNT(value)=0 THEN '*nil*'
ELSE '*sequence*'
END)
FROM datasingle
WHERE otherid=myid GROUP BY key;

How to create a column for even and odd records dynamically?

I have a query in Teradata. I want to add an additional column that would be a VARCHAR.
It should say whether the selected record is even or odd
select id, name, CASE newColumn WHEN --- ???
from my table
Like this
id name newColumn
1 asdf odd
2 ts df even
32 htssdf odd
4 asdfsd even
23 gftht odd
How can I do this
Based on your example, I can't tell how you are sorting the results. You would need to define a sort order. Let's assume you would do it based on the id number.
SELECT id, name,
ROW_NUMBER() OVER(ORDER BY id) row_id,
CASE WHEN ROW_NUMBER() OVER(ORDER BY id) MOD 2 = 0 THEN 'Even' ELSE 'Odd' END newColumn
FROM my table
The row_id is incrementally assigned based on the id field being sorted ascending. You then use the MOD function to determine if there's a remainder after dividing the number by a value (in this case 2). Result would look like the following:
id name row_id newColumn
1 asdf 1 Odd
2 ts df 2 Even
4 asdfsd 3 Odd
23 gftht 4 Even
32 htssdf 5 Odd

Resources