Table column to row mysql query - mysql

I have 2 tables i need the result table almost converted from column to row converted
Table 1 : master_table
master_id user_name
1 name1
2 name2
3 name3
4 name4
Table 2 : master_meta_table
id master_id meta_key meta_value
1 1 f_name fname1
2 2 f_name fname2
3 2 l_name lname2
4 2 age age2
5 3 l_name lnam3
6 3 age age3
7 4 sex male
I would like to get the result like this
master_id user_name f_name l_name age sex
1 name1 fname1
2 name2 fname2 lname2 age2
3 name3 lname3 age3
4 name4 fname4 male
Please some one help me with this...

Try:
select
mt1.master_id,
mt1.user_name,
max(case when mt2.meta_key = 'f_name' then mt2.meta_value end) as fname,
max(case when mt2.meta_key = 'l_name' then mt2.meta_value end) as lname,
max(case when mt2.meta_key = 'age' then mt2.meta_value end) as age,
max(case when mt2.meta_key = 'sex' then mt2.meta_value end) as sex
from
master_table mt1
join master_meta_table mt2 on mt1.master_id = mt2.master_id
group by
mt1.master_id,
mt1.user_name
Fiddle: http://sqlfiddle.com/#!2/af277e/3/0

Here is your DDL
create table master_table
(
master_id int,
user_name varchar(20)
);
create table master_meta_table
(
id int,
master_id int,
meta_key varchar(20),
meta_value varchar(20)
);
insert into master_table
values (
1,'name1');
insert into master_table
values (
2,'name2');
insert into master_table
values (
3,'name3');
insert into master_table
values (
4,'name4');
insert into master_meta_table
values (
1,1,'f_name','fname1');
insert into master_meta_table
values (
2,2,'f_name','fname2');
insert into master_meta_table
values (
3,2,'l_name','lname2');
insert into master_meta_table
values (
4,2,'age','age2');
insert into master_meta_table
values (
5,3,'l_name','lname3');
insert into master_meta_table
values (
6,3,'age','age3');
insert into master_meta_table
values (
7,4,'sex','male');
your query
select
mt.master_id,
mt.user_name,
max (case when mmt.meta_key = 'f_name' then mmt.meta_value end) as fname,
max (case when mmt.meta_key = 'l_name' then mmt.meta_value end) as lname,
max (case when mmt.meta_key = 'age' then mmt.meta_value end) as age,
max (case when mmt.meta_key = 'sex' then mmt.meta_value end) as sex
from
master_table mt,master_meta_table mmt
where mt.master_id = mmt.master_id
group by mt.master_id,mt.user_name
http://sqlfiddle.com/#!4/55845/8

Related

Count Age With Distinctly in MySQL

I have a table like this
PersonID Gender Age CreatedDate
================================
1 M 32 10/09/2011
2 F 33 10/09/2011
2 F 33 10/11/2011
1 M 32 10/11/2011
3 F 33 10/11/2011
I want to find Gender Count By Age with group by created date,The age range will be 30-34 and getting person will be distinctly.
Desired output should like this:
Gender AgeRange CreatedDate CountResult
================================
M 30_34 10/09/2011 1
F 30_34 10/09/2011 1
F 30_34 10/11/2011 1
So I tried this but couldtn help:
SELECT t.Gender,'30_34' AS AgeRange,t.CreatedDate,
SUM(CASE WHEN t.Age BETWEEN 30 AND 34 THEN 1 ELSE 0 END) AS CountResult,
FROM (
SELECT DISTINCT PersonID,Gender,Age,CreatedDate
FROM MyTable
GROUP PersonID,Gender,Age,CreatedDate
HAVING COUNT(PersonID)=1
) t
What can I do for solution?
Thanks
If you are want the earliest created date per personid this might do
drop table if exists mytable;
create table mytable(PersonID int, Gender varchar(1),Age int, CreatedDate date);
insert into mytable values
(1 , 'M', 32 , '2011-09-10'),
(2 , 'F', 33 , '2011-09-10'),
(2 , 'F', 33 , '2011-11-10'),
(1 , 'M', 32 , '2011-11-10'),
(3 , 'F', 33 , '2011-11-10');
select mt.gender,
mt.createddate,
sum(case when mt.age between 32 and 34 then 1 else 0 end) as Age32to34
from mytable mt
where createddate = (select min(mt1.createddate) from mytable mt1 where mt1.personid = mt.personid)
group by gender,mt.createddate
How about:
SELECT
Gender
, '30_34' AS AgeRange
, CreatedDate
, COUNT(*) AS CountResult
FROM MyTable A
JOIN (
SELECT PersonID, MIN(CreatedDate) MinCreatedDate
FROM MyTable GROUP BY PersonID
) B ON B.PersonID = A.PersonID AND B.MinCreatedDate = A.CreatedDate
WHERE Age BETWEEN 30 AND 34
GROUP BY Gender, CreatedDate
ORDER BY CreatedDate, Gender DESC
You would appear to want:
SELECT t.Gender, '30_34' AS AgeRange, t.CreatedDate,
COUNT(DISTINCT t.PersonId) AS CountResult
FROM MyTable
WHERE t.Age BETWEEN 30 AND 34
GROUP BY t.Gender, t.CreatedDate;

Do not retrieve if all or one of the supplied category is existing

I have below database and my problem is that I want to query all list_id in my_list table where its corresponding list_risk_code is '600' and its info_risk_code are all '400'
table: my_info_list
info_id list_id
1 1
2 1
3 1
4 2
5 2
6 3
7 3
table: my_info
info_id info_risk_code
1 '400'
2 '600'
3 '400'
4 '600'
5 '600'
6 '400'
7 '400'
table: my_list
list_id list_risk_code
1 '600'
2 '600'
3 '600'
My desired output below, because, list_id 1 has 3 info_risk_code(400,600 and 400) but one of them is 600 so it wont be included. the list_id 2 has 2 info_risk_code(600,600) but both of them are 600 so it is disregarded also. only list_id 3 is retrieve because it has 2 info_risk_code which are both 400:
my_list.list_id info_risk_code list_risk_code
3 '600' '400'
right now my code is below which gets 1 and 3 for they both contain non-600 info_risk_code. which is incorrect :
SELECT DISTINCT
ml.list_id
,info_risk_code as c_rr
,list_risk_code as a_rr
FROM
my_list AS ml
INNER JOIN my_info_list AS mil ON mil.list_id = ml.list_id
INNER JOIN my_info AS mi ON mil.info_id = mi.info_id
WHERE
(
(info_risk_code = '600' OR info_risk_code = '360')
AND (NOT list_risk_code = '600' AND NOT list_risk_code = '360')
)
OR
(
(NOT info_risk_code = '600' AND NOT info_risk_code = '360')
AND (list_risk_code = '600' OR list_risk_code = '360')
)
for your trial/reference you can use this:
CREATE TABLE my_info_list(
info_id INT,
list_id INT
);
CREATE TABLE my_info(
info_id INT,
info_risk_code varchar(5)
);
CREATE TABLE my_list(
list_id INT,
list_risk_code varchar(5)
);
INSERT INTO my_info_list VALUES (1,1);
INSERT INTO my_info_list VALUES (2,1);
INSERT INTO my_info_list VALUES (3,1);
INSERT INTO my_info_list VALUES (4,2);
INSERT INTO my_info_list VALUES (5,2);
INSERT INTO my_info_list VALUES (6,3);
INSERT INTO my_info_list VALUES (7,3);
INSERT INTO my_info VALUES (1,'400');
INSERT INTO my_info VALUES (2,'600');
INSERT INTO my_info VALUES (3,'400');
INSERT INTO my_info VALUES (4,'600');
INSERT INTO my_info VALUES (5,'600');
INSERT INTO my_info VALUES (6,'400');
INSERT INTO my_info VALUES (7,'400');
INSERT INTO my_list VALUES (1,'600');
INSERT INTO my_list VALUES (2,'600');
INSERT INTO my_list VALUES (3,'600');
Coding for almost an hour now with this query, need some idea. Thank you
You can use NOT EXISTS:
SELECT DISTINCT ml.list_id, info_risk_code as c_rr, list_risk_code as a_rr
FROM my_list AS ml
INNER JOIN my_info_list AS mil
ON mil.list_id = ml.list_id
INNER JOIN my_info AS mi
ON mil.info_id = mi.info_id
WHERE mi.info_risk_code = '400' AND
NOT EXISTS (SELECT 1
FROM my_info_list AS mil2
INNER JOIN my_info AS mi2 ON mil2.info_id = mi2.info_id
WHERE mil2.list_id = ml.list_id AND mi2.info_risk_code <> '400')
Demo here
You can use a group by query to only select list_id values where all info_risk_codes are 400 and the associated list_risk_code is 600
select ml.list_id
from my_list ml
join my_info_list mil on ml.list_id = mil.list_id
join my_info mi on mil.info_id = mi.info_id
where ml.list_risk_code = '600'
group by ml.list_id
having sum(info_risk_code <> '400') = 0
http://sqlfiddle.com/#!9/4b9e9/1

Loop through table records

I have a table with a list of names in it as below
+----------+
| CLI_NAME |
+----------+
| A |
| B |
| C |
| D |
| E |
+----------+
I'd like to loop through this something like
for each value in CLI_NAME do
{
bla bla
}
For each value in the table CLI_NAMES, I'd like to loop through and execute the below.
The value selected from the table above needs to go in as a parameter to T_NAME such as T_NAME = "abc" in the query below
INSERT INTO TABLE_2(DATE, O_WT)
SELECT
F_DATE,
CASE
WHEN
SUM(
CASE
WHEN
F_NAME like 'ty%asd%'
THEN
F_PKEY
END
) = 1 THEN 1
WHEN
SUM(
CASE
WHEN
F_NAME like 'ty%asd%'
THEN
F_PKEY
END
) = 2 THEN 2
WHEN
SUM(
CASE
WHEN
F_NAME like 'ty%asd%'
THEN
F_PKEY
END
) BETWEEN 3 AND 5 THEN 3
WHEN
SUM(
CASE
WHEN
F_NAME like 'ty%asd%'
THEN
F_PKEY
END
) > 5 THEN 5
ELSE 0
END AS O_WT
FROM
TABLE_1
WHERE
F_NAME IN (
SELECT I_NAME from I_WD WHERE I_I_ID IN (
SELECT I_MAP_ID FROM T_T_MAP where T_MAP_ID = (
SELECT T_ID FROM TWD WHERE T_NAME = 'abc'
)
)
)
AND F_DATE between '2015-05-01' and '2015-06-01'
AND F_NAME LIKE 'ty%pr%'
GROUP BY F_DATE
How could I loop through & do this please?
If I understand correctly, you can do what you want using CROSS JOIN:
INSERT INTO TABLE_2(DATE, O_WT)
SELECT t1.F_DATE,
(CASE WHEN SUM(CASE WHEN t1.F_NAME like 'ty%asd%' THEN t1.F_PKEY END) = 1 THEN 1
WHEN SUM(CASE WHEN t1.F_NAME like 'ty%asd%' THEN t1.F_PKEY END) = 2 THEN 2
WHEN SUM(CASE WHEN t1.F_NAME like 'ty%asd%' THEN t1.F_PKEY END) BETWEEN 3 AND 5 THEN 3
WHEN SUM(CASE WHEN t1. F_NAME like 'ty%asd%' THEN t1.F_PKEY END) > 5 THEN 5
ELSE 0
END)
END AS O_WT
FROM TABLE_1 t1 CROSS JOIN
CLI_NAMES
WHERE t1.F_NAME IN (SELECT I_NAME
FROM I_WD
WHERE I_I_ID IN (SELECT I_MAP_ID
FROM T_T_MAP
WHERE T_MAP_ID = (SELECT T_ID
FROM TWD
WHERE T_NAME = 'abc'
)
)
) AND
t1.F_DATE between '2015-05-01' and '2015-06-01' AND
t1.F_NAME LIKE 'ty%pr%'
GROUP BY t1.F_DATE
So you want 'abc' in WHERE T_NAME = 'abc' replaced with the CLI_NAME?
Does this suffice:
select i_map_id from t_t_map where t_map_id in
(
select t_id from twd where t_name in (select cli_name from cli_names)
)
instead of
select i_map_id from t_t_map where t_map_id =
(
select t_id from twd where t_name = 'abc'
)
It would not quite be the same as a loop. E.g. if 'A' and 'B' lead to the same t_ids, then you'd get the inserts just once instead of twice.

Group by with text and date time combination

I have a table
id col1 col2 namecol1 datetime1 teamcol1 namecol2 datetime2
1 12345 2345 name1 2014-10-13 11:57:24.713 teama
2 12345 2345 name1 2014-10-13 11:57:24.713 teamb abc 2014-11-29 09:55:38.533
3 12345 2345 name1 2014-10-13 11:57:24.713 teamb bcd 2014-12-02 06:35:38.917
4 12345 2345 name1 2014-10-13 11:57:24.713 teamc def 2014-12-22 11:57:54.863
5 12345 2345 name1 2014-10-13 11:57:24.713 teamd efg 2015-01-03 13:28:24.717
I need this output:
col1 col2 Team1 DateTime1 Team2 DateTime2 Team3 DateTime3
12345 2345 bcd 2014-12-02 06:35:38.917 def 2014-12-22 11:57:54.863 efg 2015-01-03 13:28:24.717
I tried this query:
SELECT
MAX(CASE WHEN teamcol1='teamb' THEN namecol2 END) AS Team1,
CONVERT(DATE, MAX(CASE WHEN teamcol1='teamb' THEN datetime2 END), 105) AS DateTime1,
MAX(CASE WHEN teamcol1='teamc' THEN namecol2 END) AS PRECON_AUDIT,
CONVERT(DATE,MAX(CASE WHEN teamcol1='teamc' THEN datetime2 END), 105) AS DateTime2,
MAX(CASE WHEN teamcol1 IN ('teamd') THEN namecol2 END) AS Team3,
CONVERT(DATE,MAX(CASE WHEN teamcol1 IN ('teamd') THEN datetime2 END),105) AS DateTime3,
col1, col2
FROM
(SELECT *
FROM table1) Z
WHERE
col1 = '12345'
GROUP BY
col1, col2
Output of this query:
col1 col2 Team1 DateTime1 Team2 DateTime2 Team3 DateTime3
12345 2345 abc 2014-12-02 06:35:38.917 def 2014-12-22 11:57:54.863 efg 2015-01-03 13:28:24.717
I am using SQL Server 2008.
Thanks in advance.
[EDIT]
Table1 is like audit table which will have multiple entries with different combination of col1,col2.
I need to display for each combination of col1,col2 different team names and with appropriate namecol2 and datetime2 columns.
When i use the query mentioned above it is giving me the output correctly if there is no repetition in teamcol1. If there is a repetition in teamcol1 (as mentioned in question) it is giving me the wrong namecol2.
In case of repetition in teamcol1 i need latest namecol2 and datetime2 ( from the table i need namecol2 -- bcd and datetime2 -- 2014-12-02 06:35:38.917)
At first make a list of all groups (DISTINCT col1, col2).
Then for each group find one row with the latest datetime2. Do it three times, for each teamb, teamc, teamd.
You can put complex query inside OUTER APPLY with whatever logic and ordering you need.
DECLARE #T TABLE (id int, col1 int, col2 int, namecol1 varchar(255), [datetime1] datetime, teamcol1 varchar(255), namecol2 varchar(255), [datetime2] datetime);
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (1, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teama', NULL, NULL);
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (2, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamb', 'abc', '2014-11-29 09:55:38.533');
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (3, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamb', 'bcd', '2014-12-02 06:35:38.917');
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (4, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamc', 'def', '2014-12-22 11:57:54.863');
INSERT INTO #T (id, col1, col2, namecol1, datetime1, teamcol1, namecol2, datetime2) VALUES (5, 12345, 2345, 'name1', '2014-10-13 11:57:24.713', 'teamd', 'efg', '2015-01-03 13:28:24.717');
WITH
CTE_Groups
AS
(
SELECT DISTINCT col1, col2
FROM #T
)
SELECT *
FROM
CTE_Groups
OUTER APPLY
(
SELECT TOP(1)
TT.namecol2 AS Team1
, TT.[datetime2] AS DateTime1
FROM #T AS TT
WHERE
TT.teamcol1 = 'teamb'
AND TT.col1 = CTE_Groups.col1
AND TT.col2 = CTE_Groups.col2
ORDER BY TT.[datetime2] DESC
) OA_teamb
OUTER APPLY
(
SELECT TOP(1)
TT.namecol2 AS Team2
, TT.[datetime2] AS DateTime2
FROM #T AS TT
WHERE
TT.teamcol1 = 'teamc'
AND TT.col1 = CTE_Groups.col1
AND TT.col2 = CTE_Groups.col2
ORDER BY TT.[datetime2] DESC
) OA_teamc
OUTER APPLY
(
SELECT TOP(1)
TT.namecol2 AS Team3
, TT.[datetime2] AS DateTime3
FROM #T AS TT
WHERE
TT.teamcol1 = 'teamd'
AND TT.col1 = CTE_Groups.col1
AND TT.col2 = CTE_Groups.col2
ORDER BY TT.[datetime2] DESC
) OA_teamd
Result set:
col1 col2 Team1 DateTime1 Team2 DateTime2 Team3 DateTime3
12345 2345 bcd 2014-12-02 06:35:38.917 def 2014-12-22 11:57:54.863 efg 2015-01-03 13:28:24.717
If there is no teamb for a certain combination of col1 and col2, there will be NULLs in Team1 and DateTime1. Same for teamc and teamd.

How to calculate ratio using sql query?

I have a table like below:
ID Name Department Gender
1 Crib MA MALE
2 Lucy Bsc FEMALE
3 Phil Bcom MALE
4 Ane MA FEMALE
I have 1000 row of records like this. I want to find the ratio from column Gender( MALE & FEMALE) of all students.
I need a query to perform this.
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE table1
(`ID` int, `Name` varchar(4), `Department` varchar(4), `Gender` varchar(6))
;
INSERT INTO table1
(`ID`, `Name`, `Department`, `Gender`)
VALUES
(1, 'Crib', 'MA', 'MALE'),
(2, 'Lucy', 'Bsc', 'FEMALE'),
(3, 'Phil', 'Bcom', 'MALE'),
(4, 'Ane', 'MA', 'FEMALE')
;
Query 1:
SELECT sum(case when `Gender` = 'MALE' then 1 else 0 end)/count(*) as male_ratio,
sum(case when `Gender` = 'FEMALE' then 1 else 0 end)/count(*) as female_ratio
FROM table1
Results:
| MALE_RATIO | FEMALE_RATIO |
|------------|--------------|
| 0.5 | 0.5 |
Try something like this
select sum(case when gender = 'MALE' then 1 else 0 end) / count(*) * 100 as perc_male,
sum(case when gender = 'FEMALE' then 1 else 0 end) / count(*) * 100 as perc_female
from students
This should give you the actual ratio, and should work with little or no modifcation in MySQL and SQL Server. You may have to modify the cast statement a little - my MySQL is rusty, and I think it may handle that slightly differently.
SELECT
(CAST((SELECT COUNT(*) FROM tblName WHERE Gender='MALE') AS FLOAT) /
CAST((SELECT COUNT(*) FROM tblName WHERE Gender='FEMALE') AS FLOAT))
AS ratioMaleFemale;
You're pretty close:
select (select count(*)
from table where gender='MALE' )/count(*)*100 as percentage_male,
(select count(*)
from table where gender='FEMALE' )/count(*)*100 as percentage_female
from table;
How about
select gender, count(*)
from table
group by gender
then it's very simple to calculate the ratio yourself.