How can I write this complex query SQL? - mysql

If I know how to filter by all signs of the zodiac, then by the sign of the zodiac 'Capricorn' (from December 22 to January 20) I do not know how to select.
Here is the structure of the tables, do I need to select all users with the sign of the zodiac 'Capricorn'?
The structure of the tables can be changed (or even add new tables if required):
CREATE TABLE IF NOT EXISTS `horoscope` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL UNIQUE,
`date_start` VARCHAR(5),
`date_end` VARCHAR(5)
);
CREATE INDEX `horoscope_idx_1` ON `horoscope`(`date_start`, `date_end`);
CREATE TABLE IF NOT EXISTS `user` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
`birthday` DATE NOT NULL
);
Insert test data
# Insert horoscope in table
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Aries', '03-21', '04-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Taurus', '04-21', '05-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Gemini', '05-22', '06-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Cancer', '06-22', '07-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Leo', '07-23', '08-23');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Virgin', '08-24', '09-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Libra', '08-23', '10-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Scorpio', '10-23', '11-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Sagittarius', '11-22', '12-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Capricorn', '12-22', '01-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Aquarius', '01-21', '02-19');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Pisces', '02-20', '03-20');
# Insert random user in table
DROP PROCEDURE IF EXISTS `add_user`;
CREATE PROCEDURE `add_user`(IN `count_user` INT)
LANGUAGE SQL
DETERMINISTIC
SQL SECURITY DEFINER
COMMENT 'A procedure for inserting random user'
BEGIN
DECLARE i INT DEFAULT (
SELECT `id`
FROM `user`
ORDER BY `id` DESC
LIMIT 1
);
IF i IS NULL
THEN SET i = 1;
END IF;
SET `count_user` = `count_user` + i;
WHILE i <= `count_user` DO
SET #`name` = CONCAT('user_', i);
SET #`user_birth` = '1980-01-01' + INTERVAL (RAND() * 365 * 20) DAY;
INSERT INTO `user` (`name`, `birthday`) VALUES (#`name`, #`user_birth`);
SET i = i + 1;
END WHILE;
END;
CALL `add_user`(1000);
DROP PROCEDURE IF EXISTS `add_user`;

I decided =)
SELECT *
FROM user as u
WHERE (
DATE_FORMAT(u.birthday, '%m%d') >= (
SELECT
CONCAT(LEFT(`h`.`date_start`, 2), RIGHT(`h`.`date_start`, 2))
FROM horoscope h
WHERE h.name = 'Capricorn'
) AND DATE_FORMAT(u.birthday, '%m%d') <= 1231
) OR (
DATE_FORMAT(u.birthday, '%m%d') >= 101 AND DATE_FORMAT(u.birthday, '%m%d') <= (
SELECT
CONCAT(LEFT(`h`.`date_end`, 2), RIGHT(`h`.`date_end`, 2))
FROM horoscope h
WHERE h.name = 'Capricorn'
)
);

If the boundaries of each zodiac sign are fixed dates, then it would make sense to add birth-sign as an attribute to each user instead of filtering by dates each and every time you need that information.
However I would suggest the following if you do need to filter:
select *
from user u
inner join horoscope h
where (h.date_start > h.date_end
and u.birthday between str_to_date(concat(year(u.birthday)-1, h.date_start),'%Y%m-%d')
and str_to_date(concat(year(u.birthday), h.date_end),'%Y%m-%d')
)
or (h.date_start < h.date_end
and u.birthday between str_to_date(concat(year(u.birthday), h.date_start),'%Y%m-%d')
and str_to_date(concat(year(u.birthday), h.date_end),'%Y%m-%d')
)
Note however that the indexing of the 2 varchar(5) columns in horoscope probably isn't going to be helpful to your queries.
see: https://rextester.com/OAOTEH65480

Related

how can I form a stored procedure in mysql, which can first check multiple values on multiple tables and then insert into db if true

The actual problem statement looks like :
• Product(prod_id, prod_name, qty_on_hand)
• Order(cust_id, prod_id, order_date, qty_ordered)
• Customer(cust_id, cust_name, phone, address)
"Write a stored procedure to take the cust_id, prod_id and qty_ordered as
input. Procedure should check if the order for a particular customer can be
fulfilled and if yes then insert the new order and update the product
quantity on hand. Display appropriate message if the order cannot be
fulfilled.
Output parameter must have updated value of the qty_on_hand"
I am new to plsql so ignore silly mistakes. I tried to code something like this :
delimiter $$
-- creating procedure
CREATE PROCEDURE order_request( cust_id int, prod_id int, qty_ordered int)
BEGIN
IF( customer.cust_id != cust_id AND product.prod_id != prod_id AND qty_ordered > product.qty_on_hand) THEN
SELECT 'invalid details' ;
ELSE INSERT INTO `orders` (`cust_id`, `prod_id`, `order_date`, `qty_ordered`) VALUES (cust_id, prod_id, current_date(), qty_ordered) ;
END IF ;
END $$
CALL order_request(3,3,2)$$
which showing me error : unknown table customer in field list
I have solved the question. Here is the solution:
CREATE DATABASE shopping;
USE shopping;
CREATE TABLE product( prod_id INT PRIMARY KEY, prod_name varchar(20), qty_on_hand INT CHECK(qty_on_hand >= 0));
CREATE TABLE customer( cust_id INT PRIMARY KEY, cust_name varchar(20), phone INT, address varchar(20) );
-- product table insertion
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('1', 'mug', '2');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('2', 'bowl', '15');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('3', 'plate', '7');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('4', 'fork', '40');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('5', 'spoon', '30');
-- customer table insertion
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('1', 'duke', '1212121212', 'pune');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('2', 'finn', '190120138', 'waterland');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('3', 'buck', '98989898', 'delhi');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('4', 'larry', '738197232', 'jaipur');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('5', 'edna', '184194791', 'mumbai');
CREATE TABLE orders( cust_id INT, prod_id INT, order_date DATE, qty_ordered INT CHECK(qty_ordered > 0) , FOREIGN KEY (cust_id) REFERENCES customer(cust_id), FOREIGN KEY (prod_id) REFERENCES product(prod_id));
-- orders table insertion
INSERT INTO `orders` (`cust_id`, `prod_id`, `order_date`, `qty_ordered`) VALUES ('1', '2', '2022-09-15', '2');
delimiter $$
-- creating procedure
CREATE PROCEDURE order_request( cust_id_param INT, prod_id_param INT, qty_ordered_param INT)
BEGIN
IF EXISTS (SELECT cust_id,prod_id,qty_on_hand FROM customer,product WHERE cust_id = cust_id_param AND prod_id = prod_id_param AND qty_on_hand >= qty_ordered_param)
THEN INSERT INTO `orders` (`cust_id`, `prod_id`, `order_date`, `qty_ordered`) VALUES (cust_id_param, prod_id_param, current_date(), qty_ordered_param);
UPDATE `product` SET product.qty_on_hand = qty_on_hand - qty_ordered_param WHERE prod_id = prod_id_param ;
ELSE SELECT 'invalid details' ;
END IF ;
END $$
CALL order_request(1,1,2)$$ -- valid
CALL order_request(3,2,14)$$ -- valid
CALL order_request(5,4,4)$$ -- valid
CALL order_request(10,10,2)$$ -- invalid
select * from orders$$
select * from product$$
-- creating the funtion
CREATE FUNCTION order_details (cust_id_param INT, prod_id_param INT ) RETURNS INT
BEGIN
DECLARE ans int;
SELECT SUM(qty_ordered) INTO ans FROM orders WHERE cust_id = cust_id_param AND prod_id = prod_id_param;
RETURN ans;
END$$
-- calling the funtion
SELECT order_details(5,4)$$

SQL: Selecting/Ignoring records on the basis of tables in an array

Given the following schema:
CREATE TABLE Test
(`id` int, `TestName` varchar(7), `description` varchar(55));
INSERT INTO Test
(`id`, `TestName`, `description`)
VALUES
(1, 'Test1', 'Td1'),(2, 'Test2', 'Td2'),(3, 'Test3', 'Td2');
CREATE TABLE Forcedata
(`id` int, `ForceData` varchar(7), `description` varchar(55));
INSERT INTO Forcedata
(`id`, `ForceData`, `description`)
VALUES
(1, 'F1', 'Fd1'), (2, 'F2', 'Fd2'), (3, 'F3', 'Fd3');
CREATE TABLE Temp
(`id` int, `TempName` varchar(7), `description` varchar(55));
INSERT INTO Temp
(`id`, `TempName`, `description`)
VALUES
(1, 'Tm1', 'Tmd1'),(2, 'Tm2', 'Tmd2');
CREATE TABLE Sensor
(`id` int, `SensorName` varchar(7), `description` varchar(55));
INSERT INTO Sensor
(`id`, `SensorName`, `description`)
VALUES
(1, 'S1', 'Sd1'),(2, 'S2', 'Sd2');
I want to write a select statement that gets the value from the tables mentioned in one array and this data should not be in any table of the other array. I want to do something like this:
DECLARE #ListToCheck VARCHAR(MAX)
SET #ListToCheck = 'Test' + ', ' + 'Forcedata';
DECLARE #TablesToavoid VARCHAR(MAX)
SET #TableToAvoid = 'Temp' + ', ' + 'Sensor';
SELECT id FROM
tables in ('+#ListToCheck+')'
And WHERE id should NOT be IN ('+#TablesToAvoid+')'
SO for the above schema only record with id:3 should be selected. thanks in advance :)
Try this,
MySQL:
SELECT t.id
FROM (
SELECT ID
FROM Test
UNION
SELECT ID
FROM Forcedata
) T
LEFT JOIN (
SELECT ID
FROM TEMP
UNION
SELECT ID
FROM Sensor
) T1 ON T.id = T1.id
WHERE t1.id IS NULL
SQL Server:
SELECT ID
FROM Test
UNION
SELECT ID
FROM Forcedata
EXCEPT
(
SELECT ID
FROM TEMP
UNION
SELECT ID
FROM Sensor
)

Getting List of records with No related records MySQL

I wish to know which team in "TX" have not played a game. (In other words Im looking for a selection of records where there is no related record in the many table.)
Here is the SQL:
(Or if You prefer the sql fiddle is here:http://sqlfiddle.com/#!2/14106 )
CREATE TABLE `Team` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`State` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
CREATE TABLE `Games` (
`ID` INT NOT NULL AUTO_INCREMENT,
`Team_ID` INT NULL ,
`Game_Day` DATE NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Team` (`Name`, `State`) VALUES ('Rams', 'TX');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Rockets', 'OK');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Bombers', 'TX');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Yellow Jackets', 'NV');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Wildcats', 'CT');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Miners', 'CO');
INSERT INTO `Team` (`Name`, `State`) VALUES ('Bolts', 'TX');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('2', '2013-03-16');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('2', '2013-01-01');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('3', '2013-04-16');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('5', '2013-02-02');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('4', '2013-02-12');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('6', '2013-01-09');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('6', '2013-01-01');
INSERT INTO `Games` (`Team_ID`, `Game_Day`) VALUES ('3', '2013-05-01');
I should get the result:
ID Name
1 Rams
7 Bolts
SELECT `ID`, `Name` FROM `TEAM`
WHERE `ID` NOT IN (SELECT DISTINCT(`Team_ID`) from `Games`)
AND `State` = 'TX';
SqlFiddle here.
Use an outer join, selecting only those rows that don't match
SELECT t.*
FROM TEAM t
LEFT JOIN GAMES g ON g.team_id = t.id
WHERE t.state = 'TX'
AND g.team_id is null -- return only rows that *don't* join
This this running in SQL Fiddle
Note that using a join will out-perform a sub-query approach, especially when data sets become large.
You can also left-join to the Games table and filter for where there isn't a corresponding Games row. This is usually faster than NOT IN when the tables have a lot of rows:
SELECT Team.ID, Team.Name
FROM Team
LEFT JOIN Games ON Team.ID = Games.Team_ID
WHERE Team.State = 'TX' AND Games.ID IS NULL;
If there isn't a Games row to go with the Teams row, the Games.ID column will be null in the result, so if you filter on Games.ID IS NULL you'll get all the rows where a team has no games.
There's a SQL Fiddle here.
Hope this would help.
select t.ID,t.NAME
FROM Team t
WHERE t.state = 'TX'
AND t.id NOT IN (SELECT g.TEAM_ID FROM Games g)

Getting a list of records who's

I would like to have a list of all the players in a sports league who are on a team that only has a single member.
Here is the sql:
CREATE TABLE `formsfiles`.`Teams` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Teams` (`Name`) VALUES ('Sharks');
INSERT INTO `Teams` (`Name`) VALUES ('Jets');
INSERT INTO `Teams` (`Name`) VALUES ('Fish');
INSERT INTO `Teams` (`Name`) VALUES ('Dodgers');
INSERT INTO `Teams` (`Name`) VALUES ('Pigs');
CREATE TABLE `Players` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
`Team_ID` INT NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Jim', '1');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Tom', '1');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Harry', '2');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Dave', '2');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Tim', '3');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Trey', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Jay', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Steve', '4');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Ziggy', '5');
INSERT INTO `Players` (`Name`, `Team_ID`) VALUES ('Chris', '4');
The Result should give me:
ID Name
5 Tim
9 Ziggy
Not sure how to get them grouped up?
If you want to return the players on a team with only one member you can use:
select p.id, p.name
from players p
where p.Team_ID in (select Team_ID
from players p
group by Team_ID
having count(Team_ID) = 1);
See SQL Fiddle with Demo
Edit, you can also use (moving from comment):
select max(id) id, max(name) name
from players
group by team_id
having count(team_id) = 1;
See SQL Fiddle with Demo
Thanks Bluefeet:
this work wonderfully:
I want to post it here in case someone serches itin the future:
select max(id) id, max(name) name
from players
group by team_id
having count(team_id) = 1;

Ordering Records by the contents of Related Table

I have two tables. One for Salesman and the other for Sales I wish to order the output of the query by the ALPHA sort of the Name of the salesman.
Here is the Table structure:
CREATE TABLE `Salesman` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Name` VARCHAR(45) NULL ,
PRIMARY KEY (`ID`) );
INSERT INTO `Salesman` (`Name`) VALUES ('Bill');
INSERT INTO `Salesman` (`Name`) VALUES ('John');
INSERT INTO `Salesman` (`Name`) VALUES ('Dave');
INSERT INTO `Salesman` (`Name`) VALUES ('Mark');
CREATE TABLE `Sales` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`Item` INT VARCHAR(45) NULL ,
`Salemesman_ID` INT NULL ,
`Total` INT NUll ,
PRIMARY KEY (`ID`) );
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES ('Pen', '3', '14');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES ('Rat', '1', '12');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES ('Car', '2', '1230');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES('Rabbit', '2', '11');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES('Towel', '1', '6');
INSERT INTO `Sales` (`Item`, `Salemesman_ID`, `Total`) VALUES('VaporWare', '4','900');
Because the Names in Salesmen in Alpha order are: Bill, Dave, John, Mark
I need the output to be
Rat 1 12 (Bill = 1)
Towel 1 6 (Bill = 1)
Pen 3 14 (Dave = 3)
Car 2 1230 (John = 2)
Rabbit 2 11 (John = 2)
VaporWare 4 900 (Mark = 4)
You can do what you want by joining the tables together:
select s.*
from sales s join
SalesMan sm
on s.Salesman_Id = sm.Id
order by sm.name, sm.id;
I feel the need to add that the table name "Salesman" seems unnecessarily restrictive to only half the human race.