Substring index with dynamic value and 1 column result - mysql

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.

Related

SQL: How to group data while concating records of one colum

I have following problem:
My data is ungrouped in the form of
productid
category
attribute
attributvalue
product1
cat A
length
20cm
product2
cat A
length
40cm
product3
cat A
width
20cm
product4
cat B
length
30cm
I want to have the data kind of grouped while concating the records of the values like
category
length
width
height
attribute x
y
z
cat A
20cm, 40cm
20cm
...
...
...
...
cat B
30cm
Can somebody pls help me here?
Thx a lot
Look at the data you have. You repeat the name of the attribute, which violates the third normal form, as it's an unnecessary data redundancy. You will need to refactor your database structure. Create the following tables:
attribute (id, attribute_name)
product_attribute (id, attribute_id, value)
Modify your table so it has this structure: product (id, category, product_attribute_id)
and then you can join product - product_attribute - attribute and group by category, using group_concat for the attributes.
How to get the columns? Simple:
SELECT attribute_name
FROM attributes;
Let's generate some stuff form this:
SELECT CONCAT('CASE WHEN attribute_name = \'', attribute.attribute_name, '\' THEN attribute.attribute_name ELSE NULL END AS \'', attribute.attribute_name, '\'')
FROM attribute;
So, you will need to use a cursor in order to iterate the results and that will be a SELECT clause that you generate. Let's see how the text to be generated should look alike:
/*SELECT CLAUSE HERE BASED ON THE INSTRUCTIONS ABOVE*/
FROM attribute
JOIN product_attribute
ON attribute.id = product_attribute.attribute_id
JOIN product
ON product_attribute_id = product.product_attribute_id
GROUP BY category;
and then EXECUTE this text. Yes, it is not straight-forward and yes, you will need to restructure your database, normalize your tables and migrate your data as a prerequisite for this solution, but INMHO keeping your database not normalized would be harmful by itself.

SQL select DISTINCT values from multiple columns

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;

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')";

Some doubts about this simple INNER JOIN query?

I have the following doubt about this simple INNER JOIN query.
I have these two tables that have to be joined togheter:
The first table is named VulnerabilityFix and contains the following columns:
Id: int identity
FixName: varchar
Vendor: varchar
Title: varchar
Version: varchar
The second table is named VulnerabilityAlertDocument_VulnerabilityFix (this bind the previous table to another table, but this is not important at this time) and contains the following columns:
VulnerabilityAlertDocumentId: int
VulnerabilityFixId: int
Now, on my DB the VulnerabilityFix table contains only an empty record (this record have an id but all the other fields are empty\null), infact if I perform a select *, I obtain:
select * from VulnerabilityFix
Id FixName Vendor Title Version
1
Into the VulnerabilityAlertDocument_VulnerabilityFix I have something like this:
select * from VulnerabilityAlertDocument_VulnerabilityFix
VulnerabilityAlertDocumentId VulnerabilityFixId
78385 1
78386 1
....................................................
....................................................
....................................................
78398 1
Ok, so I want JOIN toghert these 2 table in in such a way that passing the value of the VulnerabilityAlertDocumentId field of the VulnerabilityAlertDocument_VulnerabilityFix table, I obtain all the related record in the VulnerabilityFix table.
So in this case I aspect to retrieve the previous only record that having an id (having a value equal to 1) and all the other fields are empty\null.
So my query is:
SELECT VF.* FROM VulnerabilityAlertDocument_VulnerabilityFix VAD_VF
INNER JOIN VulnerabilityFix VF ON VAD_VF.VulnerabilityAlertDocumentId = VF.Id
WHERE VAD_VF.VulnerabilityAlertDocumentId = 1
The problem is that when I execute this query I obtain an empty set of records and not the unique record that I expetc to obtain.
Why? What am I missing?
Tnx
I think your query should be more like:
SELECT VF.* FROM VulnerabilityAlertDocument_VulnerabilityFix VAD_VF
INNER JOIN VulnerabilityFix VF ON VAD_VF.VulnerabilityFixId = VF.Id
WHERE VAD_VF.VulnerabilityAlertDocumentId = 78385
That is, you are using the wrong column at your ON condition since VulnerabilityFixId seems to be the foreign key over VulnerabilityFix.Id and not VulnerabilityAlertDocumentId.
On the other hand, I can't see any VulnerabilityAlertDocument_VulnerabilityFix.VulnerabilityAlertDocumentId with value 1 in you data set (where condition)

Inner join A on B if B not empty, else A

Two tables:
prefix ( id, value )
---------------------
1 'hello'
2 'good afternoon'
3 'good night'
suffix ( id, value )
---------------------
1 'world'
3 'world'
I'd like to get
all from table prefix which can be joined on table suffix via id
result should look like:
prefix.id prefix.value
--------------------------
1 'hello'
3 'good night'
well - quite easy so far...
but if table suffix is empty I'd like everything from table prefix
without subselects/ctes or if.... and in one query fulfilling both conditions!
Is there any trick to get this done by some magic having-clause or tricky something else?
Just for testcases: SQL-fiddle
Well, there is a way, but I agree with others that your requirements make no (practical) sense.
Anyway, here you go:
Join the suffix table twice (each time with a left join). One join is on the id column, the other on an always true condition.
Group the results on the prefix columns you want in the output and at least one non-nullable column of the first instance of suffix.
In the HAVING clause, put a condition that the first suffix column is not null or the number of values of a non-nullable column in the second suffix instance is 0. (Obviously, every group will have the same number of rows, i.e. the count will be the same for every prefix row.)
This is the query:
SELECT prefix.id, prefix.value
FROM prefix
LEFT JOIN suffix ON prefix.id = suffix.id
LEFT JOIN suffix AS test ON 1=1
GROUP BY prefix.id, prefix.value, suffix.id
HAVING suffix.id IS NOT NULL OR COUNT(test.id) = 0;
And there's also a demo at SQL Fiddle.
You need an OR and NOT EXISTS:
SELECT
prefix.id, prefix.value
FROM
prefix
WHERE
EXISTS(SELECT 1 from suffix WHERE prefix.id=suffix.id)
OR NOT EXISTS(SELECT 1 FROM suffix)
Demo
I guess the answer is: no, you can't!
Or if you can: No, you shouldn't.