i have a mysql table category with a field events as varchar which its values is like this : 11,29,32.and this values referer to event table ID. ( so i can say : i have a several event ID from event table in category table)
So i want to select events from category like that :
SELECT *
FROM
event e, category c
where e.event_id in (c.events)
But that not give the correct result instead when i put the values manually like :
SELECT *
FROM
event e, category c
where e.event_id in (11,29,32)
I hope that's clear,
Any help please
Part of your problem is the way that you have set up your tables. Typically you will have an events, category and then a join table between the two. You should not store data in a comma separated list to query against.
If you cannot alter your table structure, then you can use the MySQL function FIND_IN_SET():
SELECT *
FROM event e
INNER JOIN category c
on find_in_set(e.event_id, c.events)
See SQL Fiddle with Demo
If you can alter your tables, then the structure should be:
create table events
(
event_id int not null auto_increment primary key,
event_name varchar(50) not null
);
create table category
(
cat_id int not null auto_increment primary key,
cat_name varchar(50) not null
);
create table events_category
(
event_id int not null,
category_id int not null,
PRIMARY KEY(event_id, category_id),
constraint fk_event
foreign key (event_id) references events (event_id),
constraint fk_category
foreign key (category_id) references category (cat_id)
);
Then when you query the data you would use:
select *
from events e
left join events_category ec
on e.event_id = ec.event_id
left join category c
on ec.category_id = c.cat_id
You can use FIND_IN_SET:
SELECT *
FROM event e INNER JOIN category c
ON FIND_IN_SET(e.event_id, c.events)
FIND_IN_SET returns 0 if e.event_id is not present in c.events, otherwise it returns its position. If the resulting value is greater than 0, the join will succeed.
It looks like you're trying to create a many-to-many relationship between categories and events. If that's the case, you really need to refactor your design to include a table that maps this relationhsip.
category
--------
- id
- name
event
-----
- id
- name
category_to_event
-----------------
- id
- category_id
- event_id
Creating this type of structure will allow you to perform the queries you seek.
Related
I need to make a query, where there are columns of client's names and their orders per month.
Some clients don't have orders at some months and there fields must have 0.
The problem is, when i use WHERE and OUTER JOIN (no matter which one) at one query*, nessesary zero`s cutteed by WHERE. So how can i solve that?
Descripton of tables are pinned.
SELECT name
, ordering.id_client
, COUNT(order_date)
FROM ordering
RIGHT
OUTER
JOIN client
ON client.id_client = ordering.id_client
WHERE month(order_date) = 1
GROUP
BY name;
**Descripton**: (https://i.imgur.com/TrUGOLW.png)
**Example of my query** (there are 6 notes about clients at my db, showed only 4 of 6):
(https://i.imgur.com/ABP6pP0.png)
**MRE stuff**
Client: create table client(id_client int primary key auto_increment, name var char(50), passport_code int, addr varchar(70));
insert into client values(null, 'Penny Anderson', 6485, 'New Orlean');
Ordering: create table ordering(id_order int primary key auto_increment, id_client int, order_date date, foreign key(id_client) references client(id_client));
insert into ordering values(null, 1, date('2020-05-01'));
Try a simple left join starting from client's table
SELECT client.name
, client.id_client
, COUNT(order_date)
FROM client
LEFT JOIN ordering ON client.id_client = ordering.id_client
AND month(ordering.order_date) = 1
GROUP BY client.id_client;
If the condition for join is related to the left joined table then add this condition in the related ON clause and not in where otherwise this work as an inner join
I have created a database of 3 tables: "products", "brands" and "categories".
products table has product_id, brand_id, category_id, etc. So by using category_id and brand_id from other tables, I can pick up and show the different data from product table.
However, I want a solution like, for example, what if a product lies in two or more categories? What should be the database model and what table changes should I need to do more in my database?
My table structures are listed below:
Database:
Brand table:
Category table:
Product table:
Mapping cardinalities between product and category table are many to many. So you have to create a new table to keep records product and category relationship according to database normalization. SO remove category_id from the product table and create a table like as the below. For example
create table productCategory(
product_id integer references product_table(product_id),
category_id interger references category_table(category_id),
primary key (product_id,category_id)
);
there is two solution from my logic:
Change type of cat_id column in product table, using VARCHAR or TEXT, so each product have cat_id with separated by comma or colon, example value: 1,4,5
Remove column cat_id from product table, Add another table for mapping product into cat_id, example scheme:
CREATE TABLE product_mapping (
id INT(11) NOT NULL AUTO_INCREMENT,
product_id INT(11) NOT NULL,
cat_id INT(11) NOT NULL,
PRIMARY KEY (id)
)
So.. you can query by joining 3 table for product information, with example query as below:
SELECT pm.cat_id AS m_cat_id, pm.product_id AS m_product_id, p.*, c.*
FROM product_mapping AS pm
INNER JOIN products AS p ON p.id = pm.product_id
LEFT JOIN categories AS c ON c.cat_id = pm.cat_id
WHERE pm.product_id = :produc_id
I have one table called 'vacancies' which has a 'vacancy_id' PK. It looks like this:
create table vacancies
(
vacancy_id int not null auto_increment,
org_id int not null,
name varchar(255) not null comment 'title',
vacancy_visibility_start_date datetime comment 'vacancy visibility date, when it needs to be active on the website',
vacancy_visibility_end_date datetime,
primary key (vacancy_id)
);
Following this I have a couple of other tables which are linked to this one.
create table vacancy_calendar
(
vacancy_calendar_id int not null auto_increment,
vacancy_id int,
date_from datetime not null,
date_to datetime not null,
primary key (vacancy_calendar_id)
);
create table vacancy_interests
(
vacancy_id int,
interest_id int
);
create table vacancy_skills
(
vacancy_id int,
skill_id int
);
All of these tables can contain multiple rows for the same vacancy_id.
My page has different filters which I want to process via AJAX.
I want to have one line per vacancy containing all data I need + it has to match my filtering criteria. However I am not sure how my query has to look like in order to retrieve the result I am looking for.
It is possible to filter on 'interest_id' , 'skill_id', 'date_from' and 'date_to'.
I started with the following query but I am stuck very fast:
SELECT v.*, vi.interest_id
FROM `vacancies` as v
INNER JOIN `vacancy_interests` as vi on v.vacancy_id = vi.vacancy_id
GROUP BY v.vacancy_id
This query will only return me 1 interest_id for a vacancy, even if the vacancy has 3 interest_id rows in the vacancy_interest table. If I remove the GROUP BY statement I will get 3 rows for the same vacancy which is not what I want either.
Ideally I would want the interest_id's to be each in a separate column or in the same field separated by comma's. Or if there are any other possibilities/suggestions feel free to share!
You can use group_concat for get interest_id separated by comma
SELECT v.*, group_concat(vi.interest_id)
FROM `vacancies` as v
INNER JOIN `vacancy_interests` as vi on v.vacancy_id = vi.vacancy_id
GROUP BY v.vacancy_id
Referring to you comment about add where eg:
You can add where condition
SELECT v.*, group_concat(vi.interest_id)
FROM `vacancies` as v
INNER JOIN `vacancy_interests` as vi on v.vacancy_id = vi.vacancy_id
INNER JOIN `vacancy_skills` as vs ON vs.vacancy_id = v.vacancy_id
WHERE vs.skill_id IN (4) AND vi.interest_id IN (1,3)
GROUP BY v.vacancy_id
In this case the gorup_concat is applied on the resulting rows .. because group by perform the related action on the selected resulting rows .
I need to create a sql that contains a list of users, and for each user the number they have
reviewed.
I tried this, but it didnt give the desired output because i didnt know how to work the SUM into it.
SELECT review.revID, reviewer.name FROM review , reviewer WHERE review.revID = reviewer.revID
Any assistance would be apprectiated
here are my tables
CREATE TABLE reviewer (
revID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(40),
email VARCHAR(40),
password VARCHAR(125)
);
CREATE TABLE movie (
movID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(30),
release_date date
);
CREATE TABLE review (
revID INT,
movID INT,
rating INT CHECK (rating > 0 AND rating < 10) ,
review_date datetime(6),
comment VARCHAR (300),
helpful INT,
PRIMARY KEY (revID,movID),
FOREIGN KEY (revID)
REFERENCES reviewer(revID),
FOREIGN KEY (movID)
REFERENCES movie(movID)
);
Try this query:
SELECT
count(movId) AS Total_Movie_Count,
r.name AS Reviewer_Name,
r.revId as Reviewer_Id
FROM review
INNER JOIN reviewer r on r.revId = review.revId
GROUP BY review.revId
You have to use GROUP BY for aggregated column movId. And to get the reviewer name, you have to INNER JOIN with revId.
Select count(*) as no, revId from review
Group by revId
You can use the above query
Try to use explicit join syntax (e.g. inner join, left join, cross join). Because the relationships among different tables are better explained using explicit join syntax.
SELECT
review.revID,
reviewer.name,
SUM(rating) As totalReview
FROM review
INNER JOIN reviewer ON review.revID = reviewer.revID
GROUP BY reviewer.revID;
Note: You need to use GROUP BY revID in order to get output for each reviewer.
And using aggregate function SUM along with group by will provide total rating / review for each reviewer.
Btw, MYSQL doesn't support CHECK constraint.
Say I have a one-to-many relationship, such as a table of singers, each of whom has sung number of songs:
DROP TABLE singers;
CREATE TABLE singers (
id bigint not null auto_increment,
name varchar(255) not null,
PRIMARY KEY (id)
);
INSERT INTO singers (name) VALUES ('Joe'), ('Bob');
DROP TABLE songs;
CREATE TABLE songs (
id bigint not null auto_increment,
singer_id bigint not null,
name varchar(255) not null,
PRIMARY KEY (id)
);
INSERT INTO songs (singer_id, name) VALUES (1, "foo"), (2, "bar"), (1, "baz"), (2, "quux");
Assume that the song rows are written out correctly in chronological order, so that for example I could find the most recent song that Joe sang with the query
SELECT * FROM songs WHERE singer_id = 1 ORDER BY id DESC LIMIT 1;
Now, suppose I wanted to create a MySQL view that contained a row for each singer and the most recent song sung by that singer. In other words, a table that looks like this:
singer_id singer_name song_id song_name
1 Joe 3 baz
2 Bob 4 quux
It seems like this would require integrating the ORDER BY / LIMIT clause from above into the view construction/join logic somehow -- but I can't figure out how. Is this possible?
select si.id, si.name, so.name, so.id
from singers si
inner join songs so on so.singer_id = si.id
where so.id = (select max(songs.id) from songs where songs.singer_id=si.id)
http://sqlfiddle.com/#!2/d52c4/21
I'd rather use GROUP BY for this sort of thing, so here is my solution:
(I made views for convinience, but you don't have to)
CREATE VIEW lastsongs AS
SELECT singers.id, singers.name, MAX(songs.id) AS lastsong
FROM singers
JOIN songs ON songs.singer_id = singers.id
GROUP BY singers.id, singers.name;
CREATE VIEW lastsongnames AS
SELECT lastsongs.name, songs.name AS songname
FROM lastsongs
JOIN songs ON songs.id = lastsongs.lastsong;
SELECT name, songname FROM lastsongnames;