MySQL Merge multiple colums into one 'temporary' column - mysql

I was curious about the fact, if it's possible to merge multiple columns (seperated by a comma, or something else) into one column.
So for instance, i have these tables (languages):
language_id | language_iso
1 NL
2 EN
3 GT
4 EN
(Domains)
domain_id | domain_name
1 example
And another table which links the language to a webdomain
languagetodomain_id | languagetodomain_lang | languagetodomain_domain
1 1 1
2 2 1
3 4 1
4 3 1
And retrieve them in this order (ONE column as a reminder)
domain_id | domain_name | TemporaryColumn
1 example {1,2,4,3}

This should work:
SELECT Domains.*, CONCAT('{',GROUP_CONCAT(languagetodomain_lang),'}') AS TemporaryColumn
FROM Domains
JOIN LanguageToDomain ON LanguageToDomain.languagetodomain_domain = Domains.domain_id
GROUP BY domain_id
The function GROUP_CONCAT groups values separating them by a comma. I added the brackets using normal CONCAT function.
You need to group on the domain_id so it takes all the languagetodomain_lang for each domain that you have.
I've guessed the table name for languagetodomain as you didn't provide it.

Spelled out:
Group_Concat allows you to combine data across rows.
SELECT D.Domain_Id
, D.Domain_Name
, Group_Concat(LanguageToDomain_Lang,
ORDER BY LanguageToDomain_ID DESC SEPARATOR ',') as TemporaryColumn
FROM Domains D
INNER JOIN WebDomain WD
on D.Domain_ID = WD.LanguageToDomain_ID
GROUP BY D.Domain_Id, D.Domain_Name

Related

MySQL - select product_id from 2 different tables and group results

situation:
table 1 - #__virtuemart_products
virtuemart_product_id | product_special
PRODUCTS_IDS | 0 or 1
table 2 - #__virtuemart_product_badges
virtuemart_product_id | product_badge
PRODUCTS_IDS | for this situation code 3
I have a default SQL
SELECT p.`virtuemart_product_id`
FROM `#__virtuemart_products` as p
WHERE p.`product_special` = 1;
results is product IDs like 2,3,225,...
I need modify this SQL syntax for select IDs from 2 different tables and return one column.
If I modify syntax like that:
SELECT p.`virtuemart_product_id`, badges_table.`virtuemart_product_id`
FROM `#__virtuemart_products` as p, `#__virtuemart_product_badges` as badges_table
WHERE p.`product_special` = 1 OR badges_table.`badge` = 3
Result is:
virtuemart_product_id | virtuemart_product_id
1 | 123
1 | 321
1 | 231
....
why is first column 1,1,1,...? here must be product_id, no product_special code
I need group this results into one column virtuemart_product_id
What I doing wrong?
I think what you are looking for is UNION of the IDs fetched from two different tables.
SELECT p.`virtuemart_product_id`, badges_table.`virtuemart_product_id`
FROM `#__virtuemart_products` as p, `#__virtuemart_product_badges` as
badges_table
WHERE p.`product_special` = 1 OR badges_table.`badge` = 3
What the above query is doing is, it is performing a join between the two tables with the condition that product_special should be 1 or badge should be 3. Hence, each row from one table will be joined with each row of the other table where the condition will satisfy.
To get IDs from both the tables you can get the results from each table according to condition and then perform a UNION on them. So for example
(SELECT `virtuemart_product_id` FROM `#__virtuemart_products` WHERE
`product_special` = 1)
UNION
(SELECT `virtuemart_product_id` FROM
`#__virtuemart_product_badges` WHERE `badge` = 3)
I hope this helps.

MySQL - JOIN based on value of column?

I have two tables:
Table "categories"
category | parents
1 | 5,4,1
2 | 3,2
Column parents is group of numbers divided with comma, so it could be used in query as IN(parents)
Table "categories_goods"
item | category
10 | 1
12 | 2
And I want to export data to third table - there will be all parents for every category. Result should be:
Table "categories_goods_all"
item | category
10 | 5
10 | 4
10 | 1
12 | 3
12 | 2
I have this solved in PHP, but it is slow when there is 10000 * x of rows in table categories_goods. So I am looking for pure MySQL solution. Any ideas?
Use this
Demo:
http://rextester.com/CAF76544
Query
select
g.item,
SUBSTRING_INDEX(SUBSTRING_INDEX(c.parents, ',', numbers.n), ',', -1) category1
from
(select 1 n union all
select 2 union all select 3 union all
select 4 union all select 5) numbers
INNER JOIN categories c
on CHAR_LENGTH(c.parents)
-CHAR_LENGTH(REPLACE(c.parents, ',', ''))>=numbers.n-1
inner join categories_goods g
on c.category=g.category
order by
c.category, n
Thanks to this answer to split csv to rows.
Explanation: The number table generate number 1-5. You might want to add more rows here for if needed for more parent. With its help, you can separate csv to columns. Refer the answer URL given above for the same.
Now you just need to do a join to categories_goods to fetch item corresponding to parent

SQL use of conditional AND on a join table to ensure at least two or multiple values are matched

I have a join table named languages_services that basically joins the table services and languages.
I need to find a service that is able to serve both ENGLISH (language_id=1) and ESPANOL (language_id=2).
table languages_services
------------------------
service_id | language_id
------------------------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 3
With the data provided above, I want to test for language_id=1 AND language_id=2 where the result would look like this
QUERY RESULT
------------
service_id
------------
1
Obviously it doesn't return the one with service_id=2 because it doesn't service Espanol.
Any tips on this is greatly appreciated!
SELECT
service_id
FROM
language_services
WHERE
language_id = 1
OR language_id = 2
GROUP BY
service_id
HAVING
COUNT(*) = 2
Or...
WHERE
lanaguage_id IN (1,2)
GROUP BY
service_id
HAVING
COUNT(*) = 2
If you're always looking at 2 languages you could do it with joins, but the aggregate version is easier to adapt to differing numbers of language_ids. (Add an OR, or add an item to the IN list, and change the COUNT(*) = 2 to COUNT(*) = 3, etc, etc).
Be aware, however, that this scales very poorly. And with this table structure there isn't much you can do about that.
EDIT Example using a join for 2 languages
SELECT
lang1.service_id
FROM
language_services AS lang1
INNER JOIN
language_services AS lang2
ON lang1.service_id = lang2.service_id
WHERE
lang1.language_id = 1
AND lang2.language_id = 2

How to sort items in mysql based on data from another table?

I have the following tables:
word_list:
id | word
1 | ball
2 | car
3 | small
items_word_match:
itemid | wordid | in_title | in_description
1 | 1 | 1 | 0 //The word #1 occurs once in the title of the item
1 | 3 | 0 | 2 //The word #3 occurs twice in the title of the item
3 | 3 | 1 | 2
2 | 1 | 1 | 0
search:
wordid | importance
1 | 1
2 | 5
3 | 2 //word #3 is more important than the word #1 but less so than word #2
I want to sort the items based on the keywords from the search table and how important the keywords are.
And if the keyword is in the title the importance should increase by 1 and if the word appears 2 times the importance of the word should be importance*2
Neither of those answers from Denis or Johan are correct. Instead you could use this:
select
itemid,
sum(word_importance) as item_importance
from
(select
itemid,
search.wordid,
(
in_title * (importance + 1)
+ in_description * importance
) as word_importance
from
items_word_match,
search
where
i.wordid = s.wordid
)
group by itemid
As Johan pointed out, you need to add an order clause to the end, , order by item_importance desc
Feel a bit lazy today, so I'm just going to answer the question in the title:
How to sort items in mysql based on data from another table ?
You can sort the outcome of a query by any criterium you wish.
SELECT word_list.* FROM word_list
INNER JOIN search ON (search.wordid = wordlist.id)
ORDER BY search.importance, word_list.id DESC
Note that the JOIN needed to link the two tables together can have a profound effect on which rows in the word_list table are selected, but you need to do a JOIN somehow.
Otherwise MySQL will not know what the relationship between the two tables is and cannot sort the fields.
SELECT
i.itemid
, SUM( i.in_description * s.importance
+ i.in_title * ( s.importance + 1 )
)
AS item_importance
FROM
items_word_match i
LEFT JOIN
search s
ON s.wordid = i.wordid
GROUP BY
i.itemid
ORDER BY
item_importance DESC
CORRECTION:
I used LEFT JOIN catch the case when some words do not appear in the search table. But then the importance of those words seems appropriate to be 0 and not NULL, so the SUM should be changed into:
, SUM( i.in_description * COALESCE(s.importance, 0)
+ i.in_title * COALESCE(s.importance, 1)
)
your order by clause can contain fields from any of the tables:
select table1.*
from table1
join table2 using (table1_id)
order by table2.field, table1.field, etc.

How to filter duplicates within row using Distinct/group by with JOINS

For simplicity, I will give a quick example of what i am trying to achieve:
Table 1 - Members
ID | Name
--------------------
1 | John
2 | Mike
3 | Sam
Table 1 - Member_Selections
ID | planID
--------------------
1 | 1
1 | 2
1 | 1
2 | 2
2 | 3
3 | 2
3 | 1
Table 3 - Selection_Details
planID | Cost
--------------------
1 | 5
2 | 10
3 | 12
When i run my query, I want to return the sum of the all member selections grouped by member. The issue I face however (e.g. table 2 data) is that some members may have duplicate information within the system by mistake. While we do our best to filter this data up front, sometimes it slips through the cracks so when I make the necessary calls to the system to pull information, I also want to filter this data.
the results SHOULD show:
Results Table
ID | Name | Total_Cost
-----------------------------
1 | John | 15
2 | Mike | 22
3 | Sam | 15
but instead have John as $20 because he has plan ID #1 inserted twice by mistake.
My query is currently:
SELECT
sq.ID, sq.name, SUM(sq.premium) AS total_cost
FROM
(
SELECT
m.id, m.name, g.premium
FROM members m
INNER JOIN member_selections s USING(ID)
INNER JOIN selection_details g USING(planid)
) sq group by sq.agent
Adding DISTINCT s.planID filters the results incorrectly as it will only show a single PlanID 1 sold (even though members 1 and 3 bought it).
Any help is appreciated.
EDIT
There is also another table I forgot to mention which is the agent table (the agent who sold the plans to members).
the final group by statement groups ALL items sold by the agent ID (which turns the final results into a single row).
Perhaps the simplest solution is to put a unique composite key on the member_selections table:
alter table member_selections add unique key ms_key (ID, planID);
which would prevent any records from being added where the unique combo of ID/planID already exist elsewhere in the table. That'd allow only a single (1,1)
comment followup:
just saw your comment about the 'alter ignore...'. That's work fine, but you'd still be left with the bad duplicates in the table. I'd suggest doing the unique key, then manually cleaning up the table. The query I put in the comments should find all the duplicates for you, which you can then weed out by hand. once the table's clean, there'll be no need for the duplicate-handling version of the query.
Use UNIQUE keys to prevent accidental duplicate entries. This will eliminate the problem at the source, instead of when it starts to show symptoms. It also makes later queries easier, because you can count on having a consistent database.
What about:
SELECT
sq.ID, sq.name, SUM(sq.premium) AS total_cost
FROM
(
SELECT
m.id, m.name, g.premium
FROM members m
INNER JOIN
(select distinct ID, PlanID from member_selections) s
USING(ID)
INNER JOIN selection_details g USING(planid)
) sq group by sq.agent
By the way, is there a reason you don't have a primary key on member_selections that will prevent these duplicates from happening in the first place?
You can add a group by clause into the inner query, which groups by all three columns, basically returning only unique rows. (I also changed 'premium' to 'cost' to match your example tables, and dropped the agent part)
SELECT
sq.ID,
sq.name,
SUM(sq.Cost) AS total_cost
FROM
(
SELECT
m.id,
m.name,
g.Cost
FROM
members m
INNER JOIN member_selections s USING(ID)
INNER JOIN selection_details g USING(planid)
GROUP BY
m.ID,
m.NAME,
g.Cost
) sq
group by
sq.ID,
sq.NAME