Sql for selecting from a table - mysql

I have a table like this
Id title parentId subparentId itemcategory
1 service cat1 0 0 C
2 service cat2 0 0 C
3 service subcat1 1 0 S
4 service subcat2 2 0 S
5 Item 1 1 0 I
5 Item 2 1 3 I
6 Item 3 2 4 I
I need an out put like this
service cat1
Item 1
service subcat1
Item 2
service cat2
service subcat2
Item 3
Ie, list shows the items ( category ,subcategory,Items ) in the order ascending order and if the items have any subcategory it should come under the subcategory

I think you should try something like:
SELECT
t1.title,
t2.title,
t3.title
FROM table t1
LEFT JOIN table t2 ON t1.id = t2.parentId
LEFT JOIN table t3 ON t2.id = t3.subparentId
WHERE t1.itemcategory = 'C'
AND t2.itemcategory = 'S'
AND t3.itemcategory = 'I'
;
For this case:
you should join your third table (item), directly with first table (service cat), not with second like in my example.

It's a complicated problem because there can be only one dimension in the sql query result.
But we can do a little trick here
SELECT *
FROM
(
SELECT
id,
title,
parentId,
subparentId,
itemcategory,
IF(
parentId = 0 AND subparentId = 0,
id * 10000,
IF(
subparentId = 0,
parentId * 10000 + 100 - id,
parentId * 10000 + subparentId * 100 + id
)
) AS itemOrder
FROM
table1
) allOrder
ORDER BY allOrder.itemOrder
SQL Fiddle: http://sqlfiddle.com/#!9/5f711/1/0
Increase the multiplier if you've got more rows.

Another way of doing it: http://sqlfiddle.com/#!9/bbf4d/1
(there is no need for a multiplier here)
select
concat(indent1, indent2, title) as title
from (
select
if(parentid>0,parentid,id) as id1,
case itemcategory
when 'C' then -1
when 'S' then id
when 'I' then if(subparentid>0,subparentid,0)
end as id2,
case itemcategory
when 'C' then -1
when 'S' then -1
when 'I' then id
end as id3,
case itemcategory
when 'C' then ''
when 'S' then '- - '
when 'I' then '- - '
end as indent1,
case itemcategory
when 'C' then ''
when 'S' then ''
when 'I' then '- - '
end as indent2,
title
from table1
order by id1,id2,id3
) allitems
Half of this code is for indenting so you get a nicer view. It's exactly like you requested (items are all indented equally even if they are not in the same level) but you can Fiddle with it yourself.
You can also add id1,id2,id3 in the first select to see how the order is done. The outside select is only done for viewing the title alone with indenting.
The result will be:
title
----------------------
service cat1
- - - - Item 1
- - service subcat1
- - - - Item 2
service cat2
- - service subcat2
- - - - Item 3

Related

SQL - Get rows where all columns are in a list that have the same value in another column

I have a database as follows:
drinks_id ingredients_master_id
1 2
1 3
1 4
2 2
2 4
3 5
And I'm looking for a query where I can give it a list of ingredients_master_id such as 2,4 and it returns all of the drinks_id's that have exactly 2,4.
So in this case if I gave it ingredients_master_id 2,4,5 it would return drinks_id 2 and 3. And if I gave it 5 it would return drinks_id 3.
This is what I have so far but it's currently not displaying the correct info.
SELECT DISTINCT drinks.id
FROM drinks
WHERE drinks.id NOT IN
(
SELECT drinks.id
FROM ingredients
JOIN drinks ON ingredients.drinks_id = drinks.id
WHERE ingredients.ingredients_master_id NOT IN
(
2,3,4,5,6
)
);
You probably achieve the desired result using not exists as follows:
Select t.*
From your_table t
Where t.ingredients_master_id in (2,4,5)
And not exists
(Select 1 from your_table tt
Where tt.drinks_id = t.drinks_id
And tt.ingredients_master_id not in (2,4,5))
And I'm looking for a query where I can give it a list of ingredients_master_id such as 2,4 and it returns all of the drinks_id's that have exactly 2,4.
You can use group by and having:
select drinks_id
from t
group by drinks_id
having sum( ingredients_master_id in (2, 4) ) = 2;
The "= 2" is the size of the list, so you need to adjust that for different lists.
You can use as below:
select drink_id
from (
select drink_id,listagg(ingredients_master_id,',') within group( order by ingredients_master_id) val from <Table> group by drink_id)
where case
when instr('**2,4,5**',val)> 0
Then 'Y'
else 'N'
end = 'Y';

Print parent hierarchy from same table in mysql database

I have a table category which has fields and values as shown below in MYSQL database.
id name parent sort_order
1 Men null 0
2 Women null 1
3 shirt 1 0
4 salwar 2 1
Here parent is a foreign key points to the same table. In my category list page i want to print the parent hierarchy(if any) along with the category name. can i do this in a single query.
I have tried with group_concat in mysql but not able to generate the required result.
Expected Result:
1 men
2. women
3. men>shirt
4. women> salwar
You can use a self-join:
SELECT *
FROM
(
SELECT name, 1 AS rank, sort_order
FROM category
WHERE parent IS NULL
UNION ALL
SELECT CONCAT(c1.name,
CASE WHEN c2.parent IS NOT NULL THEN CONCAT('>', c2.name) ELSE '' END), 0 AS rank, c1.sort_order
FROM category c1 LEFT JOIN category c2
ON c1.id = c2.parent
WHERE c1.parent IS NULL
) t
ORDER BY t.rank DESC, t.sort_order
SQLFiddle

SQL - Get boolean values for each matching field

I need help with SQL request.
I have 3 tables:
Table User
id name
1 Jon
2 Jack
3 Bill
Table Type
id name
1 View
2 Edit
3 Delete
Table Right
id user type
1 1 1
2 1 2
3 1 3
4 2 1
5 3 1
So table Right contains linked pairs of user-type. I need a request which gets user name, and a boolean (BIT) value for each enrty in table Type, which exists in Right table for this user. Something like this for my example tables:
Username View Edit Delete
Jon 1 1 1
Jack 1 0 0
Bill 1 0 0
Thank you very much in advance!
untested:
select name,
coalesce(select 1 from `right` where `type` = 1 and right.user = user.id, 0) as `View`,
coalesce(select 1 from `right` where `type` = 2 and right.user = user.id, 0) as `Edit`,
coalesce(select 1 from `right` where `type` = 3 and right.user = user.id, 0) as `Delete`
from User
Alternatively:
select name, coalesce(RVIEW.R, 0) as `View`, coalesce(REDIT.R, 0) as `Edit`, coalesce(RDEL.R, 0) as `Delete`
from User
left join (select 1 R from `right` where `type` = 1) RVIEW on (right.user = user.id)
left join (select 1 R from `right` where `type` = 2) REDIT on (right.user = user.id)
left join (select 1 R from `right` where `type` = 3) RDEL on (right.user = user.id)
In your example, you are using reserved words as table names.
If you want to learn more about naming conventions for table names, have a look at the links in an earlier question on Stack Overflow here
Example below shows yet another way of getting the data you want (with other names for the tables):
select person.name as Username
, max( if( person_right.type_id = 1, 1, 0 ) ) as `View`
, max( if( person_right.type_id = 2, 1, 0 ) ) as `Edit`
, max( if( person_right.type_id = 3, 1, 0 ) ) as `Delete`
from person
left outer join person_right
on person_right.user_id = person.id
group by person.name
order by person.id
Another thing that might be worth looking at is the datamodel,
because Rights are normally quite "fixed".
If anyone accidentally changes one of the names in the Type table, you might have a serious security issue.
What you can do is change the person_right table to look like this
windowid user_id view_access edit_access delete_access
1 1 1 1 1
1 2 1 0 0
1 3 1 0 0
where the primary key would be window_id+user_id allowing you to setup different rights per user in a particular window/part of your application.
Hope this helps.

MySQL: find most recent value for list of subdocuments

I have a collection content that has four columns; id, timestamp, locationID, and authorID. Here is an example of my data; in production, this is tens of millions of rows in length.
id timestamp locationID authorID
1 2012-03-01 11:52:00 1 1
2 2012-03-16 19:56:00 1 2
3 2012-04-02 11:26:00 2 1
4 2012-04-22 11:52:00 2 3
5 2012-05-19 09:48:00 2 2
6 2012-05-30 07:12:00 2 1
7 2012-06-04 19:17:00 1 2
I'd like to collect the list of authorIDs whose most recent content (ordered by timestamp) matched a specific locationID.
The correct values for a query of locationID = 2 would be: [ 1, 3 ], as authorID 1 and 3 were most recently 'seen' at locationID = 2, while authorID 2's most recent content was at locationID 1.
I can certainly execute one query per authorID, but on production the authorID array has a length >100,000. This seems terribly inefficient (especially when each 'subquery' would be hitting this multi-million row content collection), and I'm looking for a better way to emerge this data from my dataset, ideally fast enough to be executed on a page render.
Something like this? This is from SQL Server, but I think it should work in mySQL as well.
DECLARE #locationId INT
SET #locationId = 2;
SELECT *
FROM (SELECT AuthorId, Max(TimeStamp) as MaxTimeStamp
FROM Content C
WHERE LocationId = #locationId
GROUP BY AuthorId) AS CBL
LEFT JOIN Content AS C ON CBL.AuthorId = C.AuthorId
AND C.TimeStamp > CBL.MaxTimeStamp
WHERE C.AuthorId IS NULL
For locationId = 2, it returns 1 and 3; and for locationId = 1, it returns 2
Per JW (thanks!), the correct mySql approach:
SET #locationId := 2;
SELECT *
FROM (SELECT AuthorId, Max(TimeStamp) as MaxTimeStamp
FROM Content C
WHERE LocationId = #locationId
GROUP BY AuthorId) AS CBL
LEFT JOIN Content AS C ON CBL.AuthorId = C.AuthorId
AND C.TimeStamp > CBL.MaxTimeStamp
WHERE C.AuthorId IS NULL
Try derieved subquery
SELECT
*
FROM content as c
INNER JOIN(
SELECT
MAX(id) as ID
FROM content
WHERE locationID = 2
GROUP BY authorID
) as t on t.ID = c.id
SQL FIDDLE DEMO

Query to solve in mysql

My table have data like this
id from
1 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
1 532|Narendra Mallik|narendram
1 595|Bhagirathi Panda|bhagirathi
2 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
2 532|Narendra Mallik|narendram
2 595|Bhagirathi Panda|bhagirathi
2 13|Hemendra Singh|hemendras
3 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
3 595|Bhagirathi Panda|bhagirathi
3 13|Hemendra Singh|hemendras
4 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
4 595|Bhagirathi Panda|bhagirathi
5 595|Bhagirathi Panda|bhagirathi
i am trying to this
Ignore the 1st row of every id
Count w.r.t. from
Ignore if the id has one row.
Means
Count from
4 595|Bhagirathi Panda|bhagirathi
2 532|Narendra Mallik|narendram
2 13|Hemendra Singh|hemendras
In 1,2,3,4 id 1st row contains chinmay panda.So i ignore that one
Bhagirathi Panda occured 5 times but id 5 having only one row so count is 4.
similarly for others
i tried but unable to find the result
please help me to write the query
(i didn't get what should the title so i write this one. )
thanks in advance.
You want a query something like this:
select count(*), from
from t
where left(from, 2) <> '1|' and
t.id in (select id from t group by id having COUNT(*) > 1)
group by from
However, because the column names are poorly named (using SQL reserved words), you need to properly quote them.
Also, I'm assuming that by "first" you mean the ones that start with '1|'.
this query will do
SELECT
COUNT(*) `count`,
`from`
FROM (
SELECT
`from`,
IF( COALESCE( #id, 0 ) = (#id := id) , #curRow := #curRow + 1, #curRow := 1 ) curRow
FROM
Table1 ) tmp
WHERE curRow > 1
GROUP BY `from`
ORDER BY `count` desc
SQL Fiddle DEMO