SQL Constraint only if column has a specific value - sql

I would like to add a unique constraint to a sql table but only if the column has a specific value. In my case, I have Geographic IDs and Status as fields. The IDs can have multiple status but there should only be one Current (C) status per ID. Is there a way to involve a where clause to have unique values only in the case of C values?
I tried adding a UNIQUE CONSTAINT as well as a filtered index, to no avail.

In SQL Server you can create filtered indexes, e.g.:
create table dbo.Demo (
GeographicID int,
[Status] char(1)
);
create unique index IXUF_Demo_GeographicID_Current
on dbo.Demo (GeographicID)
where [Status]='C';
insert dbo.Demo (GeographicID, [Status]) values (1, 'A');
insert dbo.Demo (GeographicID, [Status]) values (1, 'A');
insert dbo.Demo (GeographicID, [Status]) values (1, 'B');
insert dbo.Demo (GeographicID, [Status]) values (1, 'B');
insert dbo.Demo (GeographicID, [Status]) values (1, 'C'); --Succeeds
insert dbo.Demo (GeographicID, [Status]) values (1, 'C'); --Fails

Related

SQL script for multiple reservations by one customer (Restaurant)

I need my SQL db to be able to hold more than one reservation for a customer.
However I get some duplicate pk errors.
Here is my SQL script: (I wanna be able to let one customer have more than 1 reserv.)
/*
db_name: Restaurant DB
update_timestamp: 6.10.2021 # 09:48
sign: The Actual Daniel
*/
DROP DATABASE IF EXISTS restaurantDB;
CREATE DATABASE restaurantDB;
USE restaurantDB;
CREATE TABLE `bill` (
`billID` int NOT NULL AUTO_INCREMENT,
`payAmount` varchar(255) NOT NULL,
PRIMARY KEY (`billID`)
);
INSERT INTO `bill` VALUES (1, '$258');
INSERT INTO `bill` VALUES (2, '$420');
INSERT INTO `bill` VALUES (3, '$114');
INSERT INTO `bill` VALUES (4, '$88');
INSERT INTO `bill` VALUES (5, '$137');
INSERT INTO `bill` VALUES (6, '$286');
INSERT INTO `bill` VALUES (7, '$97');
INSERT INTO `bill` VALUES (8, '$110');
INSERT INTO `bill` VALUES (9, '$358');
INSERT INTO `bill` VALUES (10, '$190');
CREATE TABLE `customer` (
`customerID` int NOT NULL AUTO_INCREMENT,
`firstName` varchar(255) NOT NULL,
`lastName` varchar(255) NOT NULL,
`phone` varchar(20) NOT NULL,
PRIMARY KEY (`customerID`)
);
INSERT INTO `customer` VALUES (1, 'Nero', 'Lee', '420420589');
INSERT INTO `customer` VALUES (2, 'Lucius', 'Malt', '578632221');
INSERT INTO `customer` VALUES (3, 'Aurelian', 'Keen', '639456773');
INSERT INTO `customer` VALUES (4, 'Jasmine', 'Wang', '227453891');
INSERT INTO `customer` VALUES (5, 'Sophie', 'Clinck', '905674321');
INSERT INTO `customer` VALUES (6, 'Augustus', 'Smith', '523764112');
INSERT INTO `customer` VALUES (7, 'Isabelle', 'Niaom', '786554330');
INSERT INTO `customer` VALUES (8, 'Alix', 'Black', '009886775');
INSERT INTO `customer` VALUES (9, 'Leia', 'Mudworth', '345667228');
INSERT INTO `customer` VALUES (10, 'Claudius', 'Reed', '427654221');
CREATE TABLE `meal` (
`mealID` int NOT NULL AUTO_INCREMENT,
`sides` varchar(255) NULL,
`main` varchar(255) NULL,
`beverage` varchar(255) NOT NULL,
PRIMARY KEY (`mealID`)
);
INSERT INTO `meal` VALUES (1, 'potatos', 'steak', 'wine');
INSERT INTO `meal` VALUES (2, 'ice', 'cube steak', 'spring water');
INSERT INTO `meal` VALUES (3, 'rice', 'cake', 'beer');
INSERT INTO `meal` VALUES (4, 'salad', 'pasta', 'wine');
INSERT INTO `meal` VALUES (5, 'radish', 'noodles', 'soju');
INSERT INTO `meal` VALUES (6, 'rice', 'rice', 'pumpkin juice');
INSERT INTO `meal` VALUES (7, 'butter, honey', 'steak', 'wine');
INSERT INTO `meal` VALUES (8, 'ice', 'salad', 'mineral water');
INSERT INTO `meal` VALUES (9, 'sweet potatos', 'pork', 'beer');
INSERT INTO `meal` VALUES (10, 'sourdough bread', 'fruit bowl', 'mineral water');
CREATE TABLE `order` (
`orderID` int NOT NULL,
`time` datetime NOT NULL,
PRIMARY KEY (`orderID`)
);
INSERT INTO `order` VALUES (1, '21-09-27 13:36:06');
INSERT INTO `order` VALUES (2, '21-02-14 17:18:03');
INSERT INTO `order` VALUES (3, '21-03-27 11:34:16');
INSERT INTO `order` VALUES (4, '21-07-14 15:58:32');
INSERT INTO `order` VALUES (5, '21-02-27 18:16:33');
INSERT INTO `order` VALUES (6, '21-01-14 19:28:12');
INSERT INTO `order` VALUES (7, '21-08-27 16:27:07');
INSERT INTO `order` VALUES (8, '21-06-14 11:21:09');
INSERT INTO `order` VALUES (9, '21-11-27 16:30:03');
INSERT INTO `order` VALUES (10, '21-03-14 17:22:11');
CREATE TABLE `reservation` (
`reservationID` int NOT NULL AUTO_INCREMENT,
`checkIn` datetime NOT NULL,
`checkOut` datetime NOT NULL,
`customerForeign` int NOT NULL,
PRIMARY KEY (`reservationID`),
FOREIGN KEY (`customerForeign`) REFERENCES customer(customerID)
);
INSERT INTO `reservation` VALUES (1, '21-09-27 13:24:06', '21-09-27 14:17:23', 1);
INSERT INTO `reservation` VALUES (2, '21-02-14 17:25:03', '21-02-14 19:22:14', 2);
INSERT INTO `reservation` VALUES (3, '21-03-27 11:34:16', '21-03-27 13:34:16', 3);
INSERT INTO `reservation` VALUES (4, '21-07-14 15:58:32', '21-07-14 16:58:32', 4);
INSERT INTO `reservation` VALUES (5, '21-02-27 18:16:33', '21-02-27 19:16:33', 5);
INSERT INTO `reservation` VALUES (6, '21-01-14 19:28:12', '21-01-14 20:28:12', 6);
INSERT INTO `reservation` VALUES (7, '21-08-27 16:27:07', '21-08-27 17:27:07', 7);
INSERT INTO `reservation` VALUES (8, '21-06-14 11:21:09', '21-06-14 14:21:09', 8);
INSERT INTO `reservation` VALUES (9, '21-11-27 16:30:03', '21-11-27 17:30:03', 9);
INSERT INTO `reservation` VALUES (10, '21-03-14 17:22:11', '21-03-14 19:22:11', 10);
CREATE TABLE `table` (
`tableID` int NOT NULL,
`numOfSeats` int NOT NULL,
PRIMARY KEY (`tableID`)
);
INSERT INTO `table` VALUES (1, 1);
INSERT INTO `table` VALUES (2, 2);
INSERT INTO `table` VALUES (3, 2);
INSERT INTO `table` VALUES (4, 2);
INSERT INTO `table` VALUES (5, 4);
INSERT INTO `table` VALUES (6, 4);
INSERT INTO `table` VALUES (7, 6);
INSERT INTO `table` VALUES (8, 6);
INSERT INTO `table` VALUES (9, 8);
INSERT INTO `table` VALUES (10, 12);
ALTER TABLE `bill` ADD CONSTRAINT `fk_bill_order_1` FOREIGN KEY (`billID`) REFERENCES `order` (`orderID`);
ALTER TABLE `meal` ADD CONSTRAINT `fk_meal_order_1` FOREIGN KEY (`mealID`) REFERENCES `order` (`orderID`);
ALTER TABLE `order` ADD CONSTRAINT `fk_order_customer_1` FOREIGN KEY (`orderID`) REFERENCES `customer` (`customerID`);
ALTER TABLE `reservation` ADD CONSTRAINT `fk_reservation_customer_1` FOREIGN KEY (`reservationID`) REFERENCES `customer` (`customerID`);
ALTER TABLE `table` ADD CONSTRAINT `fk_table_reservation_1` FOREIGN KEY (`tableID`) REFERENCES `reservation` (`reservationID`);
This is error I get when trying to insert new reservation for customer with ID of 1

How to select distinct multi-column values in Oracle SQL?

I am trying to get distinct values with multi column select.
Sample table:
CREATE TABLE DUP_VALUES (ID NUMBER, NAME VARCHAR2(64));
INSERT INTO DUP_VALUES values (1, 'TEST1');
INSERT INTO DUP_VALUES values (2, 'TEST1');
INSERT INTO DUP_VALUES values (3, 'TEST2');
INSERT INTO DUP_VALUES values (4, 'TEST2');
INSERT INTO DUP_VALUES values (5, 'TEST1');
INSERT INTO DUP_VALUES values (6, 'TEST1');
INSERT INTO DUP_VALUES values (7, 'TEST1');
I want to get
ID NAME
1 TEST1
3 TEST2
I tried with SELECT DISTINCT ID, NAME FROM DUP_VALUES
But, I got all values, because ID is unique.
Use aggregation:
select min(id) as id, name
from dup_values
group by name;

SQL Server: Find the group of records existing in another group of records

I'm new to SQL Server and I searched for a solution to find, if a group is included in another group.
The query result should be grp_id 2 because 'A'+'B' is included in grp 3 and 5.
The result should be the grp_id of the the groups, that are included in other groups. With this result i´ll make an update of another table, joined with the grp_id.
The result should be:
+----+
| id |
+----+
| 2 |
+----+
I stuck in SQL because I do not find a solution to compare the groups. The idea was using bitwise comparison. But for that I had to add the value of each item in a field. I think there could be an easier way.
Thank you and best regards!
Eric
create table tmp_grpid (grp_id int);
create table tmp_grp (grp_id int, item_val nvarchar(10));
insert into tmp_grpid(grp_id) values (1);
insert into tmp_grpid(grp_id) values (2);
insert into tmp_grpid(grp_id) values (3);
insert into tmp_grpid(grp_id) values (4);
insert into tmp_grpid(grp_id) values (5);
--
insert into tmp_grp(grp_id, item_val) values (1, 'A');
insert into tmp_grp(grp_id, item_val) values (2, 'A');
insert into tmp_grp(grp_id, item_val) values (2, 'B');
insert into tmp_grp(grp_id, item_val) values (3, 'A');
insert into tmp_grp(grp_id, item_val) values (3, 'B');
insert into tmp_grp(grp_id, item_val) values (3, 'C');
insert into tmp_grp(grp_id, item_val) values (4, 'A');
insert into tmp_grp(grp_id, item_val) values (4, 'C');
insert into tmp_grp(grp_id, item_val) values (4, 'D');
insert into tmp_grp(grp_id, item_val) values (5, 'A');
insert into tmp_grp(grp_id, item_val) values (5, 'B');
insert into tmp_grp(grp_id, item_val) values (5, 'E');
Geez!
Technically speaking, group one is found in all other groups right? So, first a cross join to itself would be best with the condition that the values are the same AND that the groups are different, but before we do that we need to know how many items belong to each group so that's why we have the first select as a group that includes the count of elements per group, then join that with the cross join...Hope this helps.
select distinct dist_grpid
from
(select grp_id, count(*) cc from tmp_grp group by grp_id) g
inner join
(
select dist.grp_id dist_grpid, tmp_grp.grp_id, count(*) cc
from
tmp_grp dist
cross join tmp_grp
where
dist.item_val = tmp_grp.item_val and
dist.grp_id != tmp_grp.grp_id
group by
dist.grp_id,
tmp_grp.grp_id
) cj on g.grp_id = cj.dist_grpid and g.cc = cj.cc

How to insert with loops in postgresql

I am trying to insert a number of rows to a table where values came from a select query
insert into article_rel (x_id, y_id) VALUES (12, (SELECT id from table where name = 'string')
this should be the same as executing this
insert into article_rel (x_id, y_id) VALUES (12, 1)
insert into article_rel (x_id, y_id) VALUES (12, 3)
insert into article_rel (x_id, y_id) VALUES (12, 4)
and so on.
I saw this How to use a SQL for loop to insert rows into database? but I'm not sure how can this help me
Thanks in advance,
Use this query:
INSERT INTO article_rel (x_id, y_id)
SELECT 12, id
FROM table_name
WHERE name = 'string'

How many times are the results of this common table expression evaluated?

I am trying to work out a bug we've found during our last iteration of testing. It involves a query which uses a common table expression. The main theme of the query is that it simulates a 'first' aggregate operation (get the first row for this grouping).
The problem is that the query seems to choose rows completely arbitrarily in some circumstances - multiple rows from the same group get returned, some groups simply get eliminated altogether. However, it always picks the correct number of rows.
I have created a minimal example to post here. There are clients and addresses, and a table which defines the relationships between them. This is a much simplified version of the actual query I'm looking at, but I believe it should have the same characteristics, and it is a good example to use to explain what I think is going wrong.
CREATE TABLE [Client] (ClientID int, Name varchar(20))
CREATE TABLE [Address] (AddressID int, Street varchar(20))
CREATE TABLE [ClientAddress] (ClientID int, AddressID int)
INSERT [Client] VALUES (1, 'Adam')
INSERT [Client] VALUES (2, 'Brian')
INSERT [Client] VALUES (3, 'Charles')
INSERT [Client] VALUES (4, 'Dean')
INSERT [Client] VALUES (5, 'Edward')
INSERT [Client] VALUES (6, 'Frank')
INSERT [Client] VALUES (7, 'Gene')
INSERT [Client] VALUES (8, 'Harry')
INSERT [Address] VALUES (1, 'Acorn Street')
INSERT [Address] VALUES (2, 'Birch Road')
INSERT [Address] VALUES (3, 'Cork Avenue')
INSERT [Address] VALUES (4, 'Derby Grove')
INSERT [Address] VALUES (5, 'Evergreen Drive')
INSERT [Address] VALUES (6, 'Fern Close')
INSERT [ClientAddress] VALUES (1, 1)
INSERT [ClientAddress] VALUES (1, 3)
INSERT [ClientAddress] VALUES (2, 2)
INSERT [ClientAddress] VALUES (2, 4)
INSERT [ClientAddress] VALUES (2, 6)
INSERT [ClientAddress] VALUES (3, 3)
INSERT [ClientAddress] VALUES (3, 5)
INSERT [ClientAddress] VALUES (3, 1)
INSERT [ClientAddress] VALUES (4, 4)
INSERT [ClientAddress] VALUES (4, 6)
INSERT [ClientAddress] VALUES (5, 1)
INSERT [ClientAddress] VALUES (6, 3)
INSERT [ClientAddress] VALUES (7, 2)
INSERT [ClientAddress] VALUES (8, 4)
INSERT [ClientAddress] VALUES (5, 6)
INSERT [ClientAddress] VALUES (6, 3)
INSERT [ClientAddress] VALUES (7, 5)
INSERT [ClientAddress] VALUES (8, 1)
INSERT [ClientAddress] VALUES (5, 4)
INSERT [ClientAddress] VALUES (6, 6)
;WITH [Stuff] ([ClientID], [Name], [Street], [RowNo]) AS
(
SELECT
[C].[ClientID],
[C].[Name],
[A].[Street],
ROW_NUMBER() OVER (ORDER BY [A].[AddressID]) AS [RowNo]
FROM
[Client] [C] INNER JOIN
[ClientAddress] [CA] ON
[C].[ClientID] = [CA].[ClientID] INNER JOIN
[Address] [A] ON
[CA].[AddressID] = [A].[AddressID]
)
SELECT
[CTE].[ClientID],
[CTE].[Name],
[CTE].[Street],
[CTE].[RowNo]
FROM
[Stuff] [CTE]
WHERE
[CTE].[RowNo] IN (SELECT MIN([CTE2].[RowNo]) FROM [Stuff] [CTE2] GROUP BY [CTE2].[ClientID])
ORDER BY
[CTE].[Name] ASC,
[CTE].[Street] ASC
DROP TABLE [ClientAddress]
DROP TABLE [Address]
DROP TABLE [Client]
The query is designed to get all clients, and their first address (the address with the lowest ID). This appears to me that it should work.
I have a theory about why it sometimes will not work. The statement that follows the CTE refers to the CTE in two places. If the CTE is non-deterministic, and it gets run more than once, the result of the CTE may be different in the two places it's referenced.
In my example, the CTE's RowNo column uses ROW_NUMBER() with an order by clause that will potentially result in different orderings when run multiple times (we're ordering by address, the clients can be in any order depending on how the query is executed).
Because of this is it possible that CTE and CTE2 can contain different results? Or is the CTE only executed once and do I need to look elsewhere for the problem?
It is not guaranteed in any way.
SQL Server is free to evaluate CTE each time it's accessed or cache the results, depending on the plan.
You may want to read this article:
Generating XML in subqueries
If your CTE is not deterministic, you will have to store its result in a temporary table or a table variable and use it instead of the CTE.
PostgreSQL, on the other hand, always evaluates CTEs only once, caching their results.