How do I make the columns of one table not contain the columns of another table - sql

I have a database with these two tables:
CREATE TABLE Photos(
photoId INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
url VARCHAR(200) NOT NULL UNIQUE,
uploadDate DATE NOT NULL,
title VARCHAR(80) NOT NULL,
description VARCHAR(400),
visibility ENUM ('Pública', 'Privada') NOT NULL,
PRIMARY KEY (photoId),
FOREIGN KEY (userId) REFERENCES Users (userId) ON DELETE CASCADE
);
CREATE TABLE InappropiateWords(
inappropiateWordId INT NOT NULL AUTO_INCREMENT,
word VARCHAR(80),
PRIMARY KEY (inappropiateWordId)
);
I'm asked to check that the title and/or description of a photo doesn't contain any inappropiate word. I guess I need to create a trigger but I don't know how to do it. Any help is appreciated. Thanks!

This is not a requirement that you can implement at the database level.
If you are really looking to ensure that the "description" or "title" does not contain inappropriate word, then
"What is Inappropriate" has to be defined?. This is step 1. You have a table (table 2) which I assume will store all inappropriate words.
Then when the program that inserts the picture and description/title is invoked, the code needs to take the title and description and parse the words and compare them against the "inappropriate_word" table and then decide which action to take.
The description or title might have a string of words in which case you may have to parse each word and check against the table(2).
This is not a take away solution but at least I hope this helps.

You can create a table variable that loads on page and perform a join to find those values.
CREATE TABLE #tbl_LinkedNames(
Name varchar(50)
, AssociatedNameNbr varchar(50)
, userId int
, inappropiateWordId int
)
INSERT INTO #tbl_LinkedNames(
NameNbr, AssociatedName, userId, inappropiateWordId )
VALUES
('A0001', 'badword', 1, 4),
('A0002', 'wORSEWORD', 2, 5),
('A0002', 'BADW00rds', 3, 6),
('A1001', 'badw', 4, 1),
('A2002', 'lengua', 5, 2),
('A3002', 'diferente', 6, 3)
SELECT * FROM #tbl_LinkedNames
From here it is a simple join based off the called stored procedure.
SELECT
*
FROM
Photos AS p
LEFT JOIN #tbl_LinkedNames AS t_LN ON
p.userId = t_LN.userID
AND
p.inappropiateWordId = t_LN.inappropiateWordId
LEFT JOIN InappropiateWords AS Ip ON
Ip.inappropiateWordId = t_LN.inappropiateWordId

Related

Insert into table1 using data from staging_table1 and table2, while using staging_table1 to get the data from table2

Goal: Insert all data into a table from staging table. Each piece of data in the staging table has 2 names which can be found in a separate table. By using the 2 two names, I want to find their respective IDs and insert them into the foreign keys of the main table.
Question: How do I insert the data from a staging table into a table while using data from the staging to query IDs from a separate table?
Example tables:
TABLE location:
id int PRIMARY KEY,
location varchar(255) NOT NULL,
person_oneID int FOREIGN KEY REFERENCES people(person_id),
person_twoID int FOREIGN KEY REFERENCES people(person_id)
TABLE staging_location:
id int PRIMARY KEY,
location varchar(255) NOT NULL,
p1_full_name varchar(255) NOT NULL,
p2_full_name varchar(255) NOT NULL
TABLE people:
person_id int PRIMARY KEY,
first_name varchar(255) NOT NULL,
last_name varchar(255) NOT NULL,
full_name varchar(255) NOT NULL,
This question was the closest example to what I have been looking for. Though I haven't been able to get the query to work. Here is what I've tried:
INSERT INTO location(id,location,person_oneID,person_twoID)
SELECT (l.id,l.location,p1.person_oneID,p2.person_twoID)
FROM staging_location AS l
INNER JOIN people p1 ON p1.full_name = l.p1_full_name
INNER JOIN people p2 ON p2.full_name = l.p2_full_name
Additional info: I would like to do this in the same insert statement without using an update because of the number of locations being inserted. I'm using staging tables as a result of importing data from csv files. The csv file with people didn't have an ID field, so I created one for each person by following steps similar to the first answer from this question. Please let me know if any additional information is required or if I can find the answer to my question somewhere I haven't seen.
Use this code even though I do not know what your data structure is and a duplicate field may be inserted
INSERT INTO location(id,location,person_oneID,person_twoID)
SELECT (l.id,l.location,p1.person_id as person_oneID,p2.person_id as person_twoID)
FROM staging_location AS l
INNER JOIN people p1 ON p1.full_name = l.p1_full_name
INNER JOIN people p2 ON p2.full_name = l.p2_full_name

How to find the columns that need to be indexed?

I'm starting to learn SQL and relational databases. Below is the table that I have, and it has around 10 million records. My composite key is (reltype, from_product_id, to_product_id).
What strategy should I follow while selecting the columns that needs to be indexed? Also, I have documented the operations that would be performed on the table. Please help in determining which columns or combination of columns that need to be indexed?
Table DDL is shown below.
Table name: prod_rel.
Database schema name : public
CREATE TABLE public.prod_rel (
reltype varchar NULL,
assocsequence float4 NULL,
action varchar NULL,
from_product_id varchar NOT NULL,
to_product_id varchar NOT NULL,
status varchar NULL,
starttime varchar NULL,
endtime varchar null,
primary key reltype, from_product_id, to_product_id)
);
Operations performed on table:
select distinct(reltype )
from public.prod_rel;
update public.prod_rel
set status = ? , starttime = ?
where from_product_id = ?;
update public.prod_rel
set status = ? , endtime = ?
where from_product_id = ?;
select *
from public.prod_rel
where from_product_id in (select distinct (from_product_id)
from public.prod_rel
where status = ?
and action in ('A', 'E', 'C', 'P')
and reltype = ?
fetch first 1000 rows only);
Note: I'm not performing any JOIN operations. Also please ignore the uppercase for table or column names. I'm just getting started.
Ideal would be two indexes:
CREATE INDEX ON prod_rel (from_product_id);
CREATE INDEX ON prod_rel (status, reltype)
WHERE action IN ('A', 'E', 'C', 'P');
Your primary key (which also is implemented using an index) cannot support query 2 and 3 because from_product_id is not in the beginning. If you redefine the primary key as from_product_id, to_product_id, reltype, you don't need the first index I suggested.
Why does order matter? Imagine you are looking for a book in a library where the books are ordered by “last name, first name”. You can use this ordering to find all books by “Dickens” quickly, but not all books by any “Charles”.
But let me also comment on your queries.
The first one will perform badly if there are lots of different reltype values; try raising work_mem in that case. It is always a sequential scan of the whole table, and no index can help.
I have changed the order of primary columns as shown below as per #a_horse_with_no_name 's suggestion and created only one index for (from_product_id, reltype, status, action) columns.
CREATE TABLE public.prod_rel (
reltype varchar NULL,
assocsequence float4 NULL,
action varchar NULL,
from_product_id varchar NOT NULL,
to_product_id varchar NOT NULL,
status varchar NULL,
starttime varchar NULL,
endtime varchar null,
primary key reltype, from_product_id, to_product_id)
);
Also, I have gone thorough the portal suggested by #a_horse_with_no_name. It was amazing. I came to know lot of new things on indexing.
https://use-the-index-luke.com/

Table cell to count rows in other table

I'm not entirely sure if I'm even going about this in the right manner.
MVC+EF site so i could do this in the controller but I would prefer it in the DB if possible.
I have two tables. One contains entries and one contains a list of members. I want the list of members to have a column that contains the count of how many times the member name appears in the list of entries. Can I do this in the definition of the table itself?
I know this query works:
select count(*)
from dbo.Entries
where dbo.Entries.AssignedTo = 'Bob Smith'
But is there any way of doing this? What is the correct syntax?
CREATE TABLE [dbo].[Members] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Email] NVARCHAR (500) NOT NULL,
[Count] INT = select count(*) from dbo.Entries where dbo.Entries.AssignedTo = [Name]
PRIMARY KEY CLUSTERED ([ID] ASC)
I've done some searching and have tried a few different syntax's but I'm completely lost at this point so if anyone can get me headed in the correct direction I would really appreciate it.
Thanks in advance.
You could create Members as a view combining both the Entries data and another table. (Warning: Syntax not tested)
CREATE TABLE [_member_data] (
[ID] INT IDENTITY(1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Email] NVARCHAR (500) NOT NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
);
CREATE VIEW [dbo].[Members] AS
SELECT ID, Name, Email, COUNT(*)
FROM _member_data JOIN dbo.Entries ON [Name] = [AssignedTo]
GROUP BY 1, 2, 3;
It is possible to take this even further with triggers/rules that rewrite attempted inserts into Members as inserts to the appropriate backing table. But to get the kind of expressive information that you are looking for, you really want to explore using a view.

store two values in one field sql

I have to create a table in sql where one of the columns stores awards for a movie. The schema says it should store something like Oscar, screenplay. Is it possible to store two values in the same field in SQL. If so what datatype would that be and how would you query the table for it?
It's a horrible design pattern to store more than one piece of data in a single column in a relational database. The exact design of your system depends on several things, but here is one possible way to model it:
CREATE TABLE Movie_Awards (
movie_id INT NOT NULL,
award_id INT NOT NULL,
CONSTRAINT PK_Movie_Awards PRIMARY KEY CLUSTERED (movie_id, award_id)
)
CREATE TABLE Movies (
movie_id INT NOT NULL,
title VARCHAR(50) NOT NULL,
year_released SMALLINT NULL,
...
CONSTRAINT PK_Movies PRIMARY KEY CLUSTERED (movie_id)
)
CREATE TABLE Awards (
award_id INT NOT NULL,
ceremony_id INT NOT NULL,
name VARCHAR(50) NOT NULL, -- Ex: Best Picture
CONSTRAINT PK_Awards PRIMARY KEY CLUSTERED (award_id)
)
CREATE TABLE Ceremonies (
ceremony_id INT NOT NULL,
name VARCHAR(50) NOT NULL, -- Ex: "Academy Awards"
nickname VARCHAR(50) NULL, -- Ex: "Oscars"
CONSTRAINT PK_Ceremonies PRIMARY KEY CLUSTERED (ceremony_id)
)
I didn't include Foreign Key constraints here, but hopefully they should be pretty obvious.
Anything's possible; that doesn't mean it's a good idea :)
Far better to normalize your structure and store types like so:
AwardTypes:
AwardTypeID
AwardTypeName
Movies:
MovieID
MovieName
MovieAwardType:
MovieID
AwardTypeID
You can serialize your data in Json format,store Json string, and deselialize on read. More sefer than using your own format
Data presentation does't have to be so close tied with phisical data organisation. Wouldn't it be bether to store these two data in two separate columns and then just do some kind of concatenation at the display time?
It is much less painfull to join data than to split it, if you happen to need just a screenplay, one day...

Why does this query only select a single row?

SELECT * FROM tbl_houses
WHERE
(SELECT HousesList
FROM tbl_lists
WHERE tbl_lists.ID = '123') LIKE CONCAT('% ', tbl_houses.ID, '#')
It only selects the row from tbl_houses of the last occuring tbl_houses.ID inside tbl_lists.HousesList
I need it to select all the rows where any ID from tbl_houses exists within tbl_lists.HousesList
It's hard to tell without knowing exactly what your data looks like, but if it only matches the last ID, it's probably because you don't have any % at the end of the string, so as to allow for the list to continue after the match.
Is that a database in zeroth normal form I smell?
If you have attributes containing lists of values, like that HousesList attribute, you should instead be storing those as distinct values in a separate relation.
CREATE TABLE house (
id VARCHAR NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE list (
id VARCHAR NOT NULL,
PRIMARY KEY (id),
);
CREATE TABLE listitem (
list_id VARCHAR NOT NULL,
FOREIGN KEY list_id REFERENCES list (id),
house_id VARCHAR NOT NULL,
FOREIGN KEY house_id REFERENCES house (id),
PRIMARY KEY (list_id, house_id)
);
Then your distinct house listing values each have their own tuple, and can be selected like any other.
SELECT house.*
FROM house
JOIN listitem
ON listitem.house_id = house.id
WHERE
listitem.list_id = '123'