SQL select DISTINCT values from multiple columns - mysql

I hope that I formulated tittle right.
I'm trying to make tag's for posts, like for example in instagram.
User can add up to 3 tags. I save them in each in separate database column. (tag1/tag2/tag3) and later want to display only distinct values and their count total. No matter in what column they are located.
For example I have 2 different mysql rows(posts)
row 1 have : tag1 = house, tag2 = kitchen, tag3 = null
row 2 have : tag1 = home, tag2 = garden, tag3 = house
And I want to display house(2)/kitchen(1)/garden(1)/home(1)
Result that I get : house(1)/kitchen(1)/garden(1)/home(1)/house(1) because each house are in different column.
I have database table (diy_posts):
Image
My idea of sql query:
SELECT DISTINCT p.tag1 as tag1, p.tag2 as tag2, p.tag3 as tag3,
SUM(CASE WHEN p.tag1=tag1 OR p.tag2=tag2 OR p.tag3=tag3 THEN 1 ELSE 0 END) as count FROM diy_posts p GROUP BY p.id
And displaying them like:
foreach ($diyTags as $tag) {
echo $tag['tag1']; echo $tag['count'];
echo $tag['tag2']; echo $tag['count'];
echo $tag['tag3']; echo $tag['count'];
}

You can do this by unpivoting the table:
select tag, count(*)
from ((select p.tag1 as tag from diy_posts p) union all
(select p.tag2 as tag from diy_posts p) union all
(select p.tag3 as tag from diy_posts p)
) pt
group by tag;
The need to do this suggests that you may not have the right data model. The more typical model would be:
create table postTags (
postTagid int auto_increment primary key,
postId int,
tag_number int,
tag varchar(255)
);
I do note that this will require a trigger to limit the number of tags to three -- if that is, indeed, desirable. This also makes it possible for the database to prevent duplicate tags, simply by defining a unique constraint or index.

Your Desired Output is not possible with Distinct Keyword.
Also for desired output your Table schema is wrong. it must be verticle instead of horizontal.
Still in the existing Table structure you can get desired output by doing comparision and counting process in ServerSide (PHP seems in your case).
Thats the only way in my guess to achive ouput in existing schema.
- However that will ruin performance when tag and post size increase hence you need to change your table schema or you can approach for the child table too.

Turn it into a single column and do the sum:
select tag, count(*) as counts
from
(
SELECT p.tag1 as tag FROM diy_posts
UNION ALL
SELECT p.tag2 as tag FROM diy_posts
UNION ALL
SELECT p.tag3 as tag FROM diy_posts
) tmp
GROUP BY tag;

Related

Substring index with dynamic value and 1 column result

I use mysql and have a table the name is table tag with column value like this
code tag_customer
TG001 1,2,3
TG002 2,3,4,5
and also i have master_tag table of tag name like this
id value
1 New
2 Active
3 Gold
4 Silver
5 Bronze
I would like to select the data but with the value name of this tag :
code tag_value
TG001 New,Active,gold
TG002 Active,Gold,Silver,Bronze
I tried substring index but its show results in a different column and also still need to manual declaration how many lop the substring index need to declare meanwhile the value of tag is dynamic not static
You can join the tables, group by code an use GROUP_CONCAT() to collect the tag values:
SELECT t.code,
GROUP_CONCAT(m.value ORDER BY m.id) tag_value
FROM tag t INNER JOIN master_tag m
ON FIND_IN_SET(m.id, t.tag_customer)
GROUP BY t.code;
See the demo.

How to use mysql WHERE IN for two separate tables

I have two tables
books_tbl:
blocks side-bar top-bar
23,45 3,15 11,56
pages_tbl:
id title
1 ff
3
11
15
I want to select the rows from pages_tbl where pages id has included either blocks, side-bar or tob-bar columns in books_table.
How to process this?
You should really consider fixing your table structure. Never store multiple value in a single cell. See Normalization.
As in this case you can't, try using find_in_set function.
select
from pages_tbl p
where exists (
select 1
from books_tbl b
where find_in_set(
p.id,
concat(b.blocks, ',', b.side_bar, ',', b.top_bar)
) > 0
);
Remember though that this will be slow because the server can't use index if any.
It's usually not a good idea to store comma separated values in a single field. If you really cannot change your data structure, you could use a query like this:
select p.id, p.title
from
pages_tbl p inner join books_tbl b
on (
find_in_set(p.id, b.blocks)
or find_in_set(p.id, b.side-bar)
or find_in_set(p.id, b.top-bar)
)
-- add where condition?
group by p.id, p.title

MySQL multi query in one

I have a table name user with user_id, image_id .... (and some others attribute)
Another table name image with image_id and image_name ...
I wanna search an image_id by image_name, and update to user table that image_id found
like this:
UPDATE person SET image_id = (
SELECT image_id
FROM image
WHERE image.src='02.jpg' ) WHERE person_id=2
Of course, it doesn't work. I just use that query to show you what i want.
I can use 2 queries on php code, the first get image_id, the second update it to table.
But I think there is a better way to do it.
The problem here might well be that the subselect is returning more than one row and you are trying to update only one row in the table person.
Try that:
UPDATE person SET image_id = ( SELECT distinct image_id FROM image WHERE image.src='02.jpg' ) WHERE person_id=2
Can we see the error?
I think its not right way to use the sub-query in main query, you can create trigger in MySQL database or if you would like to use by this way then:
UPDATE person
SET person.image_id = ( SELECT image_id
FROM image
WHERE image_name='02.jpg'
)
WHERE person.person_id=2
update person p set p.image_id=(select i.image_id from images i where i.src='02.jpg' limit 1 ) where p.person_id=2
step 1: use table alias ( p, i ) so your fieldnames are not ambiguously
step 2: use limit 1 on subselect -> get not more than 1 rows
Better solution is to use some logic on serverside (php/perl...) and work with two seperate querys
Hope it helps...
Thomas

[ORACLE]How can I get the foreign key values using inline view?

What I'm trying to do is get the values using inline view.
on my table "mainBoard" has columns that tgno1,tgno2,tgno3, which are foreign keys refer the table,"Tag".
the table "Tag" has only two columns tgno(NUMBER), tgname(VARCHAR2).
I wanna return values from tgno(NUMBER) to tgname(VARCHAR2) using inline view.
here's what I tried for only one value:
SELECT tag1
FROM (SELECT tgname as tag1
FROM (SELECT tgname FROM tag WHERE tgno=1));
I wanna get all three values like:
SELECT tag1, tag2, tag3
FROM (SELECT...)
the final goal is to get the values of tgname values instead of tgno1,2,3 bellow:
SELECT bno,bsubject,mno,bdate,bhit,bvote,tgno1,tgno2,tgno3,num
FROM (SELECT bno,bsubject,mno,bdate,bhit,bvote,tgno1,tgno2,tgno3,rownum as num
FROM (SELECT bno,bsubject,mno,bdate,bhit,bvote,tgno1,tgno2,tgno3
FROM mainBoard WHERE btno=1 ORDER BY bno DESC ))
WHERE num BETWEEN #{start} AND #{end}
Hope my question is understandable. Thank you in advance
You could join mainboard to tag thrice once for each foreign key relationship to tag in mainboard. Why do you have to have an inline view or was that just your approach?
SELECT MB.*, T1.tgName as Tag1Name, T2.tgName as Tag1Name, T3.tgName as Tag1Name
FROM mainboard MB
LEFT JOIN tag t1
on T1.tgno = mb.tgno1
LEFT JOIN tag t2
on T2.tgno2 = mb.tgno1
LEFT JOIN tag t3
on T3.tgno3 = mb.tgno1
WHERE MB.num BETWEEN #{start} AND #{end}
I used left joins as I don't know if all 3 tag fields in MainBoard are always populated and assumed you wanted all mainboards regardless if tagno is populated in all 3.

Select 2 different columns from 2 different tables

I'm trying to select 2 different columns (newsID from the table news and movID from the table movies) so that I can use mysql_num_rows to grab the items in those conditions.
I tried this with the code below, but it is not working. How can I fix it?
$queryy="SELECT newsID FROM ".PREFIX."news WHERE published='1'";
$queryy="UNION (SELECT movID FROM ".PREFIX."movies WHERE activated='2')";
$all=safe_query($queryy);
$gesamt=mysql_num_rows($all);
You're overwriting the variable with the second assignment. Do it all in one string assignment:
$queryy = "SELECT newsID FROM ".PREFIX."news WHERE published='1'
UNION (SELECT movID FROM ".PREFIX."movies WHERE activated='2')";