MySQL Sort By Column, Then Pull The Rest - mysql

I have a unique situation where I need to pull many records, but sort SOME at the top if they are considered "favorites"...but then I need to pull all the rest of the records below this group.
Can this be done in one query...or will I need two? Any examples?

You can have a custom Order By with a CASE/WHEN clause:
Schema:
create table music
( mId int auto_increment primary key,
song varchar(100) not null
);
create table person
( pId int auto_increment primary key,
pName varchar(100) not null
);
create table person_owns_music
( id int auto_increment primary key,
mId int not null,
pId int not null,
favorite int not null,
rating int not null, -- 100 loves it. 0 hates it
foreign key `pom_2_music` (mId) references music(mId),
foreign key `pom_2_person` (pId) references person(pId)
);
-- truncate table person_owns_music;
insert music(song) values ('s1'),('s2'),('s3'),('s4'),('s5'),('s6');
insert person(pName) values ('p1'),('p2'),('p3');
insert person_owns_music(mId,pId,favorite,rating) values
(1,1,1,10),(2,1,1,100),(3,1,0,65),(4,1,1,15),(6,1,1,5),
(1,2,1,10),(2,2,1,100),(5,2,1,100);
Query:
SELECT pom.mId,m.song,pom.favorite,pom.rating
FROM person_owns_music pom
JOIN music m ON m.mId=pom.mId
WHERE pom.pId=1
ORDER BY CASE pom.favorite
WHEN 1 THEN 1
WHEN 0 THEN 2
END, pom.rating DESC;
+-----+------+----------+--------+
| mId | song | favorite | rating |
+-----+------+----------+--------+
| 2 | s2 | 1 | 100 |
| 4 | s4 | 1 | 15 |
| 1 | s1 | 1 | 10 |
| 6 | s6 | 1 | 5 |
| 3 | s3 | 0 | 65 |
+-----+------+----------+--------+

Related

Need help in merging three tables foreign keys

I have created three tables like this,
1.
CREATE TABLE person (
id int NOT NULL AUTO_INCREMENT,
name varchar(50) NOT NULL,
age int,
PRIMARY KEY (id)
);
2.
CREATE TABLE address (
id int NOT NULL AUTO_INCREMENT,
city varchar(50) NOT NULL,
post_code int NOT NULL,
person_id int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (person_id) REFERENCES person(id)
);
3
CREATE TABLE subjects (
id int NOT NULL AUTO_INCREMENT,
subjects_s varchar(50) NOT NULL,
address_id int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (address_id) REFERENCES address(id)
);
Now in tables i have some informations like this:
person
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | Sohan | 17 |
| 2 | Farhan | 18 |
+----+--------+------+
address
+----+-------+-----------+-----------+
| id | city | post_code | person_id |
+----+-------+-----------+-----------+
| 1 | Tongi | 1711 | 1 |
| 2 | Dhaka | 1230 | 2 |
+----+-------+-----------+-----------+
subjects
+----+--------------------+------------+
| id | subjects_s | address_id |
+----+--------------------+------------+
| 1 | Accounting Finance | 1 |
| 2 | Physics Math | 2 |
+----+--------------------+------------+
Now I want to show all these data together. How can I do this? Please help!
You should be able to use a SQL join statement to combine these.
The syntax is detailed in the MySQL join documentation.
With your tables, your query should look something like this:
SELECT person.*, address.*, subjects.*
FROM person
JOIN address ON person.id = address.person_id
JOIN subjects ON address.id = subjects.address_id
Keep in mind, this example uses an inner join, which may not be the right type of join depending on the data in your tables. I'd recommend reading the documentation I linked above for further guidance.

Mysql: Update using select and local variable

I am looking for an update statement that will group terms by language in the following table
CREATE TABLE _tempTerms(
ID int(8) unsigned NOT NULL AUTO_INCREMENT,
TTC_ART_ID mediumint(8) unsigned,
TTC_TYP_ID mediumint(8) unsigned,
Name varchar(200),
Value varchar(200),
ID_Lang tinyint(3) unsigned,
Sequence smallint unsigned,
Group_ID int(8) unsigned DEFAULT 0,
PRIMARY KEY(TTC_ART_ID, TTC_TYP_ID, Name, Value),
UNIQUE KEY(ID)
);
All data except Group_ID is inserted into the table. I need to update the table so that I auto-generate new Group_IDs and the Group_ID for all records with same combination of TTC_ART_ID, TTC_TYP_ID and Sequence will get the same Group_ID. I guess I need a variable to store the current value for Group_ID and so far I experimented with
SET #group_id:=1;
UPDATE _tempTerms
SET Group_ID = (#group_id := #group_id + 1);
which just gives a new group_id to every new record. I believe I need a SELECT Statement somewhere to check if there is a group_id already given, but I am confused on how I go about it.
Thank you
Schema:
create database xGrpId; -- create a test db
use xGrpId; -- use it
CREATE TABLE _tempTerms(
ID int(8) unsigned NOT NULL AUTO_INCREMENT,
TTC_ART_ID mediumint(8) unsigned,
TTC_TYP_ID mediumint(8) unsigned,
Name varchar(200),
Value varchar(200),
ID_Lang tinyint(3) unsigned,
Sequence smallint unsigned,
Group_ID int(8) unsigned DEFAULT 0,
PRIMARY KEY(TTC_ART_ID, TTC_TYP_ID, Name, Value),
UNIQUE KEY(ID)
);
-- truncate table _tempTerms;
insert _tempTerms(TTC_ART_ID,TTC_TYP_ID,Name,Value,ID_Lang,Sequence) values
(1,2,'n','v1',66,4),
(1,1,'n','v2',66,4),
(1,1,'n','v3',66,3),
(1,1,'n','v4',66,4),
(1,1,'n','v5',66,4),
(1,1,'n','v6',66,3),
(2,1,'n','v7',66,4),
(1,2,'n','v8',66,4);
View them:
select * from _tempTerms order by id;
select distinct TTC_ART_ID,TTC_TYP_ID,Sequence from _tempTerms;
-- 4 rows
-- update _tempTerms set Group_ID=0; -- clear before testing
The query:
update _tempTerms t
join
( select TTC_ART_ID,TTC_TYP_ID,Sequence,#rn:=#rn+1 as rownum
from
( select distinct TTC_ART_ID,TTC_TYP_ID,Sequence
from _tempTerms
-- put your `order by` here if needed
order by TTC_ART_ID,TTC_TYP_ID,Sequence
) d1
cross join (select #rn:=0) as xParams
) d2
on d2.TTC_ART_ID=t.TTC_ART_ID and d2.TTC_TYP_ID=t.TTC_TYP_ID and d2.Sequence=t.Sequence
set t.Group_ID=d2.rownum;
Results:
select * from _tempTerms order by TTC_ART_ID,TTC_TYP_ID,Sequence;
+----+------------+------------+------+-------+---------+----------+----------+
| ID | TTC_ART_ID | TTC_TYP_ID | Name | Value | ID_Lang | Sequence | Group_ID |
+----+------------+------------+------+-------+---------+----------+----------+
| 3 | 1 | 1 | n | v3 | 66 | 3 | 1 |
| 6 | 1 | 1 | n | v6 | 66 | 3 | 1 |
| 2 | 1 | 1 | n | v2 | 66 | 4 | 2 |
| 4 | 1 | 1 | n | v4 | 66 | 4 | 2 |
| 5 | 1 | 1 | n | v5 | 66 | 4 | 2 |
| 1 | 1 | 2 | n | v1 | 66 | 4 | 3 |
| 8 | 1 | 2 | n | v8 | 66 | 4 | 3 |
| 7 | 2 | 1 | n | v7 | 66 | 4 | 4 |
+----+------------+------------+------+-------+---------+----------+----------+
Cleanup:
drop database xGrpId;
d1, d2, and xParams are derived tables. Every derived table needs a name. The purpose of xParams and the cross join is merely to bring in a variable to initialize the row number. This is because mysql lacks CTE functionality found in other RDBMS's. So, don't overthink the cross join. It is like saying LET i=0.

Deleting equal rows in mySQL 5.7.9?

I have this table in mysql called ts1
+----------+-------------+---------------+
| position | email | date_of_birth |
+----------+-------------+---------------+
| 3 | NULL | 1987-09-03 |
| 1 | NULL | 1982-03-26 |
| 2 | Sam#gmail | 1976-10-03 |
| 2 | Sam#gmail | 1976-10-03 |
+----------+-------------+---------------+
I want to drop the equal rows using ALTER IGNORE.
I have tried
ALTER IGNORE TABLE ts1 ADD UNIQUE INDEX inx (position, email, date_of_birth);
and
ALTER IGNORE TABLE ts1 ADD UNIQUE(position, email, date_of_birth);
In both cases I get
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IGNORE TABLE ts1 ADD UNIQUE(position, email, date_of_birth)' at line 1
I'm using mySQL 5.7.9. Any suggestions?
To do it inline against the table, given just the columns you show consider the below. To do it in a new table as suggested by Strawberry, see my pastie link under comments.
create table thing
( position int not null,
email varchar(100) null,
dob date not null
);
insert thing(position,email,dob) values
(3,null,'1987-09-03'),(1,null,'1982-03-26'),
(2,'SamIAm#gmail.com','1976-10-03'),(2,'SamIAm#gmail.com','1976-10-03');
select * from thing;
+----------+------------------+------------+
| position | email | dob |
+----------+------------------+------------+
| 3 | NULL | 1987-09-03 |
| 1 | NULL | 1982-03-26 |
| 2 | SamIAm#gmail.com | 1976-10-03 |
| 2 | SamIAm#gmail.com | 1976-10-03 |
+----------+------------------+------------+
alter table thing add id int auto_increment primary key;
Delete with a join pattern, deleting subsequent dupes (that have a larger id number)
delete thing
from thing
join
( select position,email,dob,min(id) as theMin,count(*) as theCount
from thing
group by position,email,dob
having theCount>1
) xxx -- alias
on thing.position=xxx.position and thing.email=xxx.email and thing.dob=xxx.dob and thing.id>xxx.theMin
-- 1 row affected
select * from thing;
+----------+------------------+------------+----+
| position | email | dob | id |
+----------+------------------+------------+----+
| 3 | NULL | 1987-09-03 | 1 |
| 1 | NULL | 1982-03-26 | 2 |
| 2 | SamIAm#gmail.com | 1976-10-03 | 3 |
+----------+------------------+------------+----+
Add the unique index
CREATE UNIQUE INDEX `thing_my_composite` ON thing (position,email,dob); -- forbid dupes hereafter
View current table schema
show create table thing;
CREATE TABLE `thing` (
`position` int(11) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`dob` date NOT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
UNIQUE KEY `thing_my_composite` (`position`,`email`,`dob`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

Mysql query of multiple tables joined

I have the following tables:
machine_machine
id | machineid
1 | EE100034442
item_item
id | upc | name
2 | 10001 | Snickers
machine_setup
id | machine_id | selection | item_id
3 | 1 | A1 | 1
Im trying to get the following output by joining the tables.
machine_setup.machine_id=machine_machine.machineid, machine_setup.selection, item_item.upc, item_item.name
EE100034442 A1 10001 Snickers
Table machine_setup will by the main referenced table as it has multiple selection for each machine_id.
Based on the only id's I can see at the moment to join on, consider this:
create table machine_machine
( id int auto_increment primary key,
machineid varchar(50) not null
);
create table item_item
( id int auto_increment primary key,
upc varchar(30) not null,
name varchar(100) not null
);
create table machine_setup
( id int auto_increment primary key,
machine_id int not null,
selection varchar(30) not null
);
insert machine_machine(machineid) values ('EE100034442');
insert item_item(upc,name) values ('10001','Snickers');
insert machine_setup(machine_id,selection) values (1,'A1'),(1,'A2'),(1,'A(n)');
select mm.machineid,ms.selection,ii.upc,ii.name
from machine_setup ms
join machine_machine mm
on mm.id=ms.machine_id
join item_item ii
on ii.id=ms.machine_id;
+-------------+-----------+-------+----------+
| machineid | selection | upc | name |
+-------------+-----------+-------+----------+
| EE100034442 | A1 | 10001 | Snickers |
| EE100034442 | A2 | 10001 | Snickers |
| EE100034442 | A(n) | 10001 | Snickers |
+-------------+-----------+-------+----------+
I'm not quite sure I understand the question, but the sql you want is like;
Select machine1.machineid, setup.Selection, item.upc, item.name
From Machine_machine machine1 --Set alias for the table
Inner Join machine_setup setup on setup.machine_id = machine1.id --This looks like a link table to me
Inner Join item_item item on setup.item_id = item.id -- in your example this wouldn't link as item_id is 1 in the machine_setup
In your example the machine_setup item_id is set to 1, which means it wouldn't link to the item_item table. i'm assuming this is a mistake.
Let me know if you need more information.

How to implement sequence number database for each group of users?

It's easy to create a database table for storing sequence numbers ; but this design is suited for the event when the sequence is shared for all users. What I want is to create sequence for each group of users : this group can grow at any time because it's a database table , that is the administrator can create a group at any time and users are assigned to a specific group. So how to implement the sequence generation according to a group ?
if you are using myisam
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
Below extracted from above links.
For MyISAM and BDB tables you can specify AUTO_INCREMENT on a
secondary column in a multiple-column index. In this case, the
generated value for the AUTO_INCREMENT column is calculated as
MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is
useful when you want to put data into ordered groups.
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
For your case:
CREATE TABLE mytable (
user_id MEDIUMINT NOT NULL AUTO_INCREMENT,
group_id MEDIUMINT NOT NULL,
user_name CHAR(30) NOT NULL,
PRIMARY KEY (group_id,user_id)
) ENGINE=MyISAM;
INSERT INTO mytable (group_id, user_name) VALUES
(1,'alex'),(1,'jenny'),(2,'baz'),(1,'tim'),(2,'danny'),(3,'joe');
SELECT * FROM mytable ORDER BY group_id,user_id;
Returns:
user_id group_id user_name
1 1 alex
2 1 jenny
3 1 tim
1 2 baz
2 2 danny
1 3 joe