SQL ORDER BY multiple fields with sub orders - mysql

I'm trying to make a query to get the list of a students class ordered by the type defined, sex and name.
I have the next query:
SELECT * FROM STUDENTS
ORDER BY FIELD(type, 'b', 'p', 'j', 'i', 'a', 'c', 'v'), FIELD(sex, 'M', 'F'), `name` ASC
I'm getting that order, first type, and then both sex from that type and name, but I need to define some types and sex together, something like this:
type = 'b', sex = 'M', name
type = 'b', sex = 'F', name
type = 'p', sex = 'M', name
type = 'p', sex = 'F', name
type = 'i', sex = 'M', name
type = 'a', sex = 'M', name
type = 'c', sex = 'M', name
type = 'v', sex = 'M', name
type = 'j', sex = 'M', name
type = 'i', sex = 'F', name
type = 'a', sex = 'F', name
type = 'c', sex = 'F', name
type = 'v', sex = 'F', name
type = 'j', sex = 'F', name

You can always use a CASE statement to create the expression you want
SQL DEMO
SELECT *
FROM Table1
ORDER BY CASE WHEN type = 'b' and sex = 'M' THEN 1
WHEN type = 'b' and sex = 'F' THEN 2
WHEN type = 'p' and sex = 'M' THEN 3
WHEN type = 'p' and sex = 'F' THEN 4
....
ELSE 9999
END,
name

Related

MySQL Join: Return items in table A with multiple specific values in the join table B [duplicate]

My table is like this:
CREATE TABLE candidate_tbl (
`name` VARCHAR(1),
`degree` VARCHAR(41),
`doneMasters` VARCHAR(6)
);
INSERT INTO candidate_tbl
(`name`, `degree`, `doneMasters`)
VALUES
('A', 'MBA', 'true'),
('A', 'MS', 'false'),
('B', 'MBA', 'true'),
('B', 'MS', 'true'),
('C', 'MBA', 'false'),
('C', 'MS', 'false'),
('D', 'MBA', 'false'),
('D', 'MS','true'),
('E', 'MBA', 'false'),
('E', 'MS', 'false'),
('F', 'MBA', 'false'),
('F', 'MS', 'true'),
('G', 'MBA', 'false'),
('G', 'MS', 'false'),
('H', 'MS', 'true'),
('H', 'MS', 'true');
I want the list of candidates who neither has MS nor MBA, which is C,E and G
I tried these 4 ways, Fiddle given here
Method-1
SELECT name,count(*) FROM candidate_tbl
WHERE doneMasters = 'false'
AND doneMasters = 'false'
GROUP BY name
HAVING count(*) = 2;
Method-2
SELECT DISTINCT name FROM candidate_tbl ct1 WHERE NOT EXISTS
(
SELECT name FROM candidate_tbl ct2 WHERE ct1.name = ct2.name and doneMasters = 'true'
);
Method-3
SELECT name FROM (SELECT name,group_concat(doneMasters) as dmf FROM candidate_tbl
GROUP BY name) dd
WHERE dmf = 'false,false';
Method-4
SELECT name FROM (SELECT name, group_concat(doneMasters) as dmf FROM candidate_tbl
GROUP BY name) dd
WHERE dmf = 'false,false';
I want to know which is the best solution in terms of performance and accuracy, or other alternate solutions.
Your data model doesn't really make sense to me. Why store negative information in a table, for instance?
The best way would be to normalize the data model to have a separate table of candidates and their degrees. Then use not exists:
select c.*
from candidates c
where not exists (select 1
from candidate_degrees cd
where cd.candidate_id = c.candidate_id and
cd.degree in ('MS', 'MBA')
);
This would be a rather dramatic change to your data model:
The degrees table would only have degrees that exist (and perhaps other information such as the year, school, and so on).
The candidates would be identified by an id that can be used for joining.
Try this.
SELECT name FROM candidate_tbl
WHERE doneMasters = 'false'
AND degree in ('MBA', 'MS')
GROUP BY name HAVING count(1) = 2;
DEMO HERE: DB-FIDDLE
the solution is simply
SELECT name FROM candidate_tbl
WHERE degree in ('MBA', 'MS') AND doneMasters = 'false'
GROUP BY name;
it will return a unique name from list who has not done MBA or MS.
If for each name there are always exactly 2 rows with values 'MBA' and 'MS' in the column degree, then there is no reason to check or filter the column degree.
The simplest way is to group by name, filter out the rows with true in the column doneMasters and check in the HAVING clause if in the results there are 2 rows (these 2 rows will contain 'false' in the column doneMasters):
SELECT name
FROM candidate_tbl
WHERE doneMasters = 'false'
GROUP BY name
HAVING COUNT(*) = 2
See the demo.
Results:
> | name |
> | :--- |
> | C |
> | E |
> | G |
Note that a flag column like doneMasters would be better (for clarity, coding simplicity, less storage space and better performance) defined as BOOLEAN.
See the demo.

MySQL query to create a report

Hello Can any one help me with this query
INSERT INTO userrole (Id, Name, Description, IsEnabled, Created, CreatedBy, Updated, UpdatedBy) VALUES
(1, 'Role_1', '', 1, '2020-04-14 18:30:00', 'Admin', NULL, NULL),
(2, 'Role_2', 'Description', 1, '2020-04-15 18:30:00', 'ADMIN', '2020-04-16 18:30:00', 'John Smith'),
(3, 'Role_3', 'Description', 0, '2020-04-15 18:30:00', 'John SMITH', '2020-04-16 18:30:00', 'Ben SMITH'),
(4, 'Role_4', 'Description', 1, '2020-04-18 18:30:00', 'bEn SmiTh', '2020-04-20 18:30:00', 'BEN SMITH');
SELECT
UPPER(CreatedBy) AS UserName,
COUNT(UPPER(CreatedBy)) AS NoOfCreatedRoles,
SUM(CASE
WHEN IsEnabled = 1 THEN 1
ELSE - 1
END) AS NoOfCreatedAndEnabledRoles,
CASE
WHEN UpdatedBy IS NOT NULL THEN COUNT(UPPER(UpdatedBy)) ELSE -1
END AS NoOfUpdatedRoles
FROM UserRole
GROUP BY CreatedBy
ORDER BY CreatedBy desc
Give a try with this:
SELECT Result.UserName, Result.NoOfCreatedRoles, Result.NoOfCreatedAndEnabledRoles, Result.NoOfUpdatedRoles
FROM (
Select UPPER(TRIM(CreatedBy)) AS 'UserName',
COUNT(UPPER(CreatedBy)) AS NoOfCreatedRoles,
SUM(CASE WHEN IsEnabled = 1 THEN 1 ELSE - 1 END) AS NoOfCreatedAndEnabledRoles,
(SELECT CASE when COUNT(*) = 0 THEN -1 ELSE Count(*) END
FROM UserRole as URQ
WHERE URQ.UpdatedBy = UR.CreatedBy) AS NoOfUpdatedRoles
FROM UserRole UR
GROUP BY CreatedBy
ORDER BY UserName
) as Result
ORDER BY NoOfCreatedRoles

Subsetting the original sql table using key pairs from a subset table

I have the following table:
CREATE TABLE test (key1 varchar(10), key2 varchar(10), col3 varchar(10),
col4 varchar(10), col5 varchar(10), val varchar(10))
INSERT INTO test VALUES('A', 'B', 'C', 'D', 'F', 'good1')
INSERT INTO test VALUES('F', 'C', 'C', 'D', 'F', 'bad1')
INSERT INTO test VALUES('A', 'D', 'C', 'D', 'F', 'good2')
INSERT INTO test VALUES('N', 'B', 'C', 'D', 'F', 'bad2')
INSERT INTO test VALUES('A', 'B', 'C', 'D', 'F', 'want this')
INSERT INTO test VALUES('A', 'D', 'C', 'D', 'F', 'and this')
I would like to extract key1, key2 pairs that where val column includes "good". Then I need to go back to the original table and extract all the entries where the mentioned key1, key2 pairs appear.
I am using the following:
select t.* from test t where exists (select 1
from t t2
where t2.value like '%good%') and
t2.key1 = t.key1 and
t2.key2 = t.key2)
Upon running the above, I get the following error:
"Object t does not exist"
You need to refer to the table as test, not t:
select t.*
from test t
where exists (select 1
from test t2
where t2.value like '%good%') and
t2.key1 = t.key1 and
t2.key2 = t.key2
);

mysql select result based on multiple matching criteria of 2 or more columns

My table is like this:
CREATE TABLE candidate_tbl (
`name` VARCHAR(1),
`degree` VARCHAR(41),
`doneMasters` VARCHAR(6)
);
INSERT INTO candidate_tbl
(`name`, `degree`, `doneMasters`)
VALUES
('A', 'MBA', 'true'),
('A', 'MS', 'false'),
('B', 'MBA', 'true'),
('B', 'MS', 'true'),
('C', 'MBA', 'false'),
('C', 'MS', 'false'),
('D', 'MBA', 'false'),
('D', 'MS','true'),
('E', 'MBA', 'false'),
('E', 'MS', 'false'),
('F', 'MBA', 'false'),
('F', 'MS', 'true'),
('G', 'MBA', 'false'),
('G', 'MS', 'false'),
('H', 'MS', 'true'),
('H', 'MS', 'true');
I want the list of candidates who neither has MS nor MBA, which is C,E and G
I tried these 4 ways, Fiddle given here
Method-1
SELECT name,count(*) FROM candidate_tbl
WHERE doneMasters = 'false'
AND doneMasters = 'false'
GROUP BY name
HAVING count(*) = 2;
Method-2
SELECT DISTINCT name FROM candidate_tbl ct1 WHERE NOT EXISTS
(
SELECT name FROM candidate_tbl ct2 WHERE ct1.name = ct2.name and doneMasters = 'true'
);
Method-3
SELECT name FROM (SELECT name,group_concat(doneMasters) as dmf FROM candidate_tbl
GROUP BY name) dd
WHERE dmf = 'false,false';
Method-4
SELECT name FROM (SELECT name, group_concat(doneMasters) as dmf FROM candidate_tbl
GROUP BY name) dd
WHERE dmf = 'false,false';
I want to know which is the best solution in terms of performance and accuracy, or other alternate solutions.
Your data model doesn't really make sense to me. Why store negative information in a table, for instance?
The best way would be to normalize the data model to have a separate table of candidates and their degrees. Then use not exists:
select c.*
from candidates c
where not exists (select 1
from candidate_degrees cd
where cd.candidate_id = c.candidate_id and
cd.degree in ('MS', 'MBA')
);
This would be a rather dramatic change to your data model:
The degrees table would only have degrees that exist (and perhaps other information such as the year, school, and so on).
The candidates would be identified by an id that can be used for joining.
Try this.
SELECT name FROM candidate_tbl
WHERE doneMasters = 'false'
AND degree in ('MBA', 'MS')
GROUP BY name HAVING count(1) = 2;
DEMO HERE: DB-FIDDLE
the solution is simply
SELECT name FROM candidate_tbl
WHERE degree in ('MBA', 'MS') AND doneMasters = 'false'
GROUP BY name;
it will return a unique name from list who has not done MBA or MS.
If for each name there are always exactly 2 rows with values 'MBA' and 'MS' in the column degree, then there is no reason to check or filter the column degree.
The simplest way is to group by name, filter out the rows with true in the column doneMasters and check in the HAVING clause if in the results there are 2 rows (these 2 rows will contain 'false' in the column doneMasters):
SELECT name
FROM candidate_tbl
WHERE doneMasters = 'false'
GROUP BY name
HAVING COUNT(*) = 2
See the demo.
Results:
> | name |
> | :--- |
> | C |
> | E |
> | G |
Note that a flag column like doneMasters would be better (for clarity, coding simplicity, less storage space and better performance) defined as BOOLEAN.
See the demo.

Topological sorting in sql

I am resolving dependency between some objects in a table.
I have to do something with objects in order their dependency.
For example, the first object doesn't depend on any object. The second and third ones depends on first one and so on. I have to use topological sorting.
Could someone show the sample of implementation so sorting in t-sql.
I have a table:
create table dependency
(
DependencyId PK
,ObjectId
,ObjectName
,DependsOnObjectId
)
I want to get
ObjectId
ObjectName
SortOrder
Thank you.
It seams, it works:
declare #step_no int
declare #dependency table
(
DependencyId int
,ObjectId int
,ObjectName varchar(100)
,DependsOnObjectId int
,[rank] int NULL
,degree int NULL
);
insert into #dependency values (5, 5, 'Obj 5', 2, NULL, NULL)
insert into #dependency values (6, 6, 'Obj 6', 7, NULL, NULL)
insert into #dependency values (2, 2, 'Obj 2', 1, NULL, NULL)
insert into #dependency values (3, 3, 'Obj 3', 1, NULL, NULL)
insert into #dependency values (1, 1, 'Obj 1', 1, NULL, NULL)
insert into #dependency values (4, 4, 'Obj 4', 2, NULL, NULL)
insert into #dependency values (7, 7, 'Obj 7', 2, NULL, NULL)
update #dependency set rank = 0
-- computing the degree of the nodes
update d set d.degree =
(
select count(*) from #dependency t
where t.DependsOnObjectId = d.ObjectId
and t.ObjectId <> t.DependsOnObjectId
)
from #dependency d
set #step_no = 1
while 1 = 1
begin
update #dependency set rank = #step_no where degree = 0
if (##rowcount = 0) break
update #dependency set degree = NULL where rank = #step_no
update d set degree = (
select count(*) from #dependency t
where t.DependsOnObjectId = d.ObjectId and t.ObjectId != t.DependsOnObjectId
and t.ObjectId in (select tt.ObjectId from #dependency tt where tt.rank = 0))
from #dependency d
where d.degree is not null
set #step_no = #step_no + 1
end
select * from #dependency order by rank
You have a simple tree structure with only one path to each ObjectId so labeling based off number of DependsOnObjectId links traversed gives only one answer and a good enough answer to process the right stuff first. This is easy to do with a common table expression and has the benefit of easy portability:
with dependency_levels as
(
select ObjectId, ObjectName, 0 as links_traversed
from dependency where DependsOnObjectId is null
union all
select ObjectId, ObjectName, links_traversed+1
from dependecy
join dependency_levels on dependency.DependsOnObjectId = dependency_levels.ObjectId
)
select ObjectId, ObjectName, links_traversed
from dependency_levels
order by links_traversed