create breadcrumb from sql closure table and calculate depth - sql

I have created a simple hierarchy with closure table and I want to create breadcrumb dynamically and also to calculate the depth.
The code for the structure is:
CREATE TABLE categories (
id int IDENTITY(1,1) not null,
created_date datetime not null DEFAULT GETDATE(),
updated_date datetime not null DEFAULT GETDATE(),
title nvarchar(max) NOT NULL,
CONSTRAINT PK_categories_id PRIMARY KEY CLUSTERED (id),
);
CREATE TABLE childcategories (
parent_id int,
child_id int,
CONSTRAINT PK_childcategories PRIMARY KEY NONCLUSTERED ([parent_id],[child_id]),
CONSTRAINT FK_childcategories_parent_id FOREIGN KEY (parent_id) REFERENCES
categories(id),
CONSTRAINT FK_childcategories_child_id FOREIGN KEY (child_id) REFERENCES
categories(id),
);
insert into categories(title)
values ('hardware'), ('cpu'), ('gpu') , ('intel'), ('amd'), ('nvidia')
insert into childcategories(parent_id,child_id)
values (1,2), (1,3),(2,4), (2,5),(3,4), (3,5), (3,6)
So far the recursive cte I have is:
with cpe as (
select c.id as parent_id,c.title as parent_title,children.id as
child_id,children.title as child_title
from categories c
inner join childcategories parents on parents.parent_id=c.id
inner join categories children on children.id=parents.child_id
union all
select children.id as parent_id,children.title as parent_title,children.id as
child_id,children.title as child_title
from cpe
inner join childcategories cteparents on cteparents.child_id=cpe.parent_id
inner join categories children on children.id=cteparents.parent_id
)
select * from cpe;

Related

how can i create constraint on table based on many column and value in another table Oracle

i have atable such as codes table have these values:
Major_code
minor_code
name
1
0
Country
1
1
USA
1
2
JOR
2
0
Food
2
1
Burger
2
2
Mansaf
I need to create table have these columns (ID, Country_ID , Food_ID) what is the best constraint that resolve this issue?
Having a single lookup table for all reference codes is a very poor design, to the point of almost being a SQL anti-pattern. It is likely to have performance issues. It is also difficult to ensure that the value of COUNTRY_MINOR_CODE references an actual country minor code in the reference table. Which brings us to this statement:
I need to create table have these columns (ID, Country_ID , Food_ID)
Can't be done. Or at least it can be done but you can't build foreign keys on that, because minor keys are not unique in the referenced table. But if you are set on a single table, say lookup_table with primary key defined on (major_code, minor code), you need this:
create table country_food (
id number primary_key
,country_major_code number not null
,country_minor_code number not null
,food_major_code number not null
,food_minor_code number not null
,constraint country_major_code_ck check (country_major_code = 1)
,constraint country_minor_code_ck check (country_minor_code != 0)
,constraint food_major_code_ck check (country_major_code = 2)
,constraint food_minor_code_ck check (country_minor_code != 0)
,constraint country_code_fk foreign key (country_major_code, country_minor_code) references lookup_table
,constraint food_code_fk foreign key (food_major_code, food_minor_code) references lookup_table
)
/
The hard coding of values, the additional check constraints, the increased complexity of joining to look up the name ... These are all reasons why you should choose to have separate tables for FOOD, COUNTRY, etc.
create table country (
country_id number primary_key
,country_name varchar2(24) not null
)
/
create table food (
food_id number primary_key
,food_name varchar2(24) not null
)
/
create table country_food (
id number primary_key
,country_id number not null
,food_id number not null
,food_major_code number not null
,constraint country_code_fk foreign key (country_id) references country
,constraint food_code_fk foreign key (food_id) references food
)
/
If I've got it right, you can get all Country+Food pairs with the query
select t1.minor_code counrty_id, t2.minor_code food_id
from (
select minor_code
from codesTable
where Major_code = (
select c.Major_code
from codesTable c
where c.minor_code=0 and c.name='Country')
) t1
cross join (
select minor_code
from codesTable
where Major_code = (
select c.Major_code
from codesTable c
where c.minor_code=0 and c.name='Food')
) t2
You can use the query to insert data into a table with an autogenerated ID or use it any other way.
First you need to consider the design of the tables
Table of country
Table of foods
Tables of food_country -------- relationship => many-to-many
CREATE TABLE Country
(
Major_code numeric(15) not null,
minor_code numeric(15),
name varchar(50),
CONSTRAINT country_pk PRIMARY KEY (Major_code)
);
CREATE TABLE Food
(
Food_ID numeric(15) not null,
//...........................
name varchar(50),
CONSTRAINT food_pk PRIMARY KEY (Food_ID)
);
CREATE TABLE Counry_Food
(
ID numeric(10) not null,
Country_ID numeric(15) not null,
Food_ID numeric(15) not null,
CONSTRAINT fk_country
FOREIGN KEY (Country_ID)
REFERENCES Country(Major_code),
CONSTRAINT fk_food
FOREIGN KEY (Food_ID)
REFERENCES supplier(Food_ID),
);

Referencing the primary table in a sub-query

I have tables with some relations:
create table Students
(
[id] uniqueidentifier not null,
primary key (id),
[group] uniqueidentifier FOREIGN KEY REFERENCES [Groups]([id]) not null,
[name] nvarchar(20),
[surname] nvarchar(20)
)
create table Books
(
[id] uniqueidentifier not null,
primary key (id),
[name] nvarchar(100) not null,
[pages] int not null,
[author] uniqueidentifier FOREIGN KEY REFERENCES [Authors]([id])
)
create table StudentsCards
(
[id] uniqueidentifier not null,
primary key (id),
[student] uniqueidentifier FOREIGN KEY REFERENCES [Students]([id])
)
create table RelationsBooksToStudentsCards
(
[book] uniqueidentifier FOREIGN KEY REFERENCES [Books]([id]) not null,
[students_card] uniqueidentifier FOREIGN KEY REFERENCES [StudentsCards]([id]) not null
)
And I have query which trying to get sum of pages by students:
SELECT
[id] AS student_id, [name], [surname],
(SELECT SUM(b.pages)
FROM Students AS s
INNER JOIN RelationsBooksToStudentsCards AS r ON (SELECT [id] FRM StudentsCards WHERE student = s.id) = r.students_card
INNER JOIN Books AS b ON r.book = b.id
WHERE s.id LIKE student_id)
FROM
Students
Question: what do I need to do to use student_id in the query? Because now I got an exception:
Invalid column name 'student_id'
Ah, it was easy:
select [id], [name], [surname], (SELECT sum(b.pages)
FROM Students as s
inner JOIN RelationsBooksToStudentsCards as r
ON (select [id] from StudentsCards where student = s.id) = r.students_card
inner JOIN Books as b
ON r.book = b.id
where s.id like myAlias.id) from Students as myAlias

How to join in sql with multiple tables (need) join multiple references?

Some table only have identity columns but this is because this is a example only.
create table producto(
idproducto int identity primary key
)
create table inventario(
idInventario id int identity primary key,
idproducto int,
foreign key (idproducto) references producto(idproducto)
)
create table sucursal(
idSucursal id int identity primary key
)
create table inventariosucursal(
idinventariosucursal id int primary key,
idsucursal int,
idinventario int,
foreign key (idsucursal) references sucursal (idsucursal),
foreign key (idinventario) references inventario (idinventario),
)
create table mejoresventasxsucursal
(
mejoresventasxsucursal id int primary key,
idsucursal int,
idproducto int,
foreign key (idsucursal) references sucursal(idsucursal),
foreign key (idproducto) references producto (idproducto)
)
What do I need?
select the stocking ( inventario table ) by every branch office (sucursal table) but only most selled products (mejoresventasxsucursal table).
the problem is mejoresventasxsucursal table does "join" with 2 tables product and sucursal but after i have other table with does "join" with same 2 tables product and sucursal.
select s.id,i.id,p.id,
from producto p
join inventario i on p.idproducto = i.idproducto
join inventariosucursal i_s on i_s.idinventario = i.idinventario
join sucursal s on i_s on i_s.idsucursal = s.idsucursal
join producto p on i.producto = p.idproducto
join mejoresventasxsucursal mv on mv.idsucursal = s.idsucursal
Here is the problem. I need join mejoresventasxsucursal with producto. I know I could do something as join producto p2 but I would like to know what is the best way for join with producto. I know other solution is in where condition doing where p.idproducto=mv.idprocucto

INSERT Conflict on Virtual Table SQL

I am having a problem on the INSERT because of a FK reference. The process goes like this:
I create the table Cuentas, and Cuentas_Con_RowNumber
I select from a huge table with over 3 million records. Because some are repeated and I need to store only 1 "cuenta", I made the tempDB. I have to do this, because on the huge db there are many records with the same Cuenta_Nro with different transactions, and I just need one.
I select from the tempDB all the columns but the RowNumber and then insert it into the Cuentas table.
The problem is that the tempDB Pais (country) column is not a FK which references to the Paises (countries) table, and on the original table (Cuentas) it does, therefore, it crashes.
Code:
CREATE TABLE Paises
(
Pais_Id numeric(18,0) PRIMARY KEY NOT NULL,
Pais_Nombre varchar(255) NOT NULL
)
CREATE TABLE Cuentas
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_Moneda varchar(255) DEFAULT 'Dolar',
Cuenta_Tipo numeric(18,0)
FOREIGN KEY REFERENCES Tipo_De_Cuentas(Tipo_De_Cuenta_Id),
Cuenta_PaisOrigen numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_PaisAsignado numeric(18, 0)
FOREIGN KEY REFERENCES Paises(Pais_Id),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Tarjeta numeric(18, 0)
FOREIGN KEY REFERENCES Tarjetas(Tarjeta_Nro),
Cuenta_Cliente numeric(18, 0)
FOREIGN KEY REFERENCES Clientes(Cliente_Id)
)
CREATE TABLE #Cuentas_Con_RowNumer
(
Cuenta_Nro numeric(18,0) PRIMARY KEY NOT NULL,
Cuenta_Estado varchar(255),
Cuenta_PaisOrigen numeric(18,0)),
Cuenta_Fec_Cre datetime,
Cuenta_Fec_Cierre datetime,
Cuenta_Cliente numeric(18,0),
Cuenta_Tarjeta numeric(18,0),
RowNumber int
)
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
Maestro.Cuenta_Numero, Maestro.Cuenta_Estado, Maestro.Cuenta_Pais_Codigo,
Maestro.Cuenta_Fecha_Creacion, Maestro.Cuenta_Fecha_Cierre, Clientes.Cliente_Id, Maestro.Tarjeta_Numero,
ROW_NUMBER() OVER (PARTITION BY Maestro.Cuenta_Numero ORDER BY Maestro.Cuenta_Numero) AS RowNumber
FROM gd_esquema.Maestra Maestro, dbo.Clientes
WHERE
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre) AS a
WHERE a.RowNumber = '1'
INSERT INTO Cuentas
(
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
)
SELECT
Cuenta_Nro, Cuenta_Estado, Cuenta_PaisOrigen, Cuenta_Fec_Cre,
Cuenta_Fec_Cierre, Cuenta_Cliente, Cuenta_Tarjeta
FROM #Cuentas_Con_RowNumer
The error message is:
Instrucción INSERT en conflicto con la restricción FOREIGN KEY "FK__Cuentas__Cuenta___24B338F0". El conflicto ha aparecido en la base de datos "GD1C2015", tabla "dbo.Paises", column 'Pais_Id'.
The issue is because Maestro.Cuenta_Pais_Codigo column is being pulled from gd_esquema.Maestra table which in turn is going as Cuenta_PaisOrigen in target table and has a foreign key defined.
There will be some records which are being selected for insert Cuentas table that doesn't have a matching Pais_Id record in dbo.Paises table.
You can add a inner join as below and check the results as :
INSERT INTO #Cuentas_Con_RowNumer
SELECT *
FROM (SELECT
...
FROM gd_esquema.Maestra Maestro
inner join dbo.Clientes on
Clientes.Cliente_Apellido = Maestro.Cli_Apellido AND
Clientes.Cliente_Nombre = Maestro.Cli_Nombre
inner join Paises P on Maestro.Cuenta_Pais_Codigo = P.Pais_Id
) AS a
WHERE a.RowNumber = '1'

Values controlled by foreign keys

I have very simple database in SQL Server, with these three tables:
Theater (ID, is3D, othervalues...)
Show (ID, Theater_ID, Movie_ID, date, time, othervalues...)
Movie (ID, is3D, othervalues...)
I would like to ensure that 3D movies can be only played in 3D theaters. 2D movies only in 2D theaters, and doing it ONLY BY foreign keys (no triggers etc.).
To do this through foreign keys alone you need to add an is3D column to Show as well and a couple of logically redundant UNIQUE constraints.
CREATE TABLE Theater
(
ID INT PRIMARY KEY,
is3D BIT NOT NULL,
/*Other columns*/
UNIQUE(ID, is3D)
)
CREATE TABLE Movie
(
ID INT PRIMARY KEY,
is3D BIT NOT NULL,
/*Other columns*/
UNIQUE(ID, is3D)
)
CREATE TABLE Show
(
ID INT PRIMARY KEY,
Theater_ID INT NOT NULL,
Movie_ID INT NOT NULL,
is3D BIT NOT NULL,
/*Other columns*/
FOREIGN KEY(Theater_ID, is3D) REFERENCES Theater (ID, is3D),
FOREIGN KEY(Movie_ID, is3D) REFERENCES Movie (ID, is3D)
)
An indexed view can also be used to enforce this declaratively without requiring the additional column or unique constraints as below.
CREATE TABLE dbo.TwoRows
(
X INT PRIMARY KEY
);
INSERT INTO dbo.TwoRows
VALUES (1), (2)
GO
CREATE VIEW V
WITH SCHEMABINDING
AS
SELECT S.Theater_ID,
S.Movie_ID
FROM dbo.Show S
JOIN dbo.Theater T
ON S.Theater_ID = T.ID
JOIN dbo.Movie M
ON S.Movie_ID = M.ID
CROSS JOIN dbo.TwoRows
WHERE T.is3D <> M.is3D
GO
CREATE UNIQUE CLUSTERED INDEX IX
ON V(Theater_ID, Movie_ID)
The underlying query should always return no rows if the rule is satisfied. If any row is returned then the cross join on dbo.TwoRows will multiply it out causing a unique constraint violation and preventing the situation.