Join Two Tables and Replace Values Where Conditions Meet - mysql

I'm trying to come with an expression to join two tables (the first two) to get something like the third one.
I want to SELECT 'Sitepage' and 'Medium' and JOIN the first two tables ON the rows where the RIGHT 5 characters are matching between 'Sitepage' and 'Campaign ID'. Additionally, IF there is a match, THEN 'Program' will REPLACE 'Medium'. What would be the Syntax?
Sitepage | Medium
xyz.com/campaign=12345 | A
xyz.com/campaign=23456 | C
Campaign ID | Program
12345 | B
Sitepage | Medium
xyz.com/campaign=12345 | B
xyz.com/campaign=23456 | C
http://i.stack.imgur.com/pq35n.png

I based my answer off of #Juan's, but I had to make some adjustments to get it to work.
SELECT
SitePage, COALESCE(t2.Program, t1.Medium) as Medium
FROM Table1 t1
LEFT JOIN Table2 t2
ON RIGHT(t1.Sitepage, 5) = COALESCE(t2.`Campaign ID`, -1);
#Abhik was heading in the right direction too. It's more generic than the one above, which assumes that the last 5 characters of SitePage will be the only pertinent ones. With that said, I would have gone with...
SELECT
SitePage, COALESCE(t2.Program, t1.Medium) as Medium
FROM Table1 t1
LEFT JOIN Table2 t2
ON SUBSTRING_INDEX(t1.Sitepage,'=',-1)
= COALESCE(t2.`Campaign ID`, -1);
SQL Fiddle example

You can use substring_index and then update by join
update table1 t1
join table2 t2 on t2.`Campaign ID` = substring_index(t1.`Sitepage`,'=',-1)
set t1.`Medium` = t2.`Program`

SELECT SitePage, ISNULL(t2.Program, t1.Medium) as Medium
FROM Table1 t1
LEFT JOIN Table2 t2 ON RIGHT(t1.Medium, 5) = t2.CampaignId
That should do the trick. Left Join on the expresion you want, when there is a match, Program will not be null so you can pick it up, otherwise pick medium. If your table2 allows null on Program you may need to tweak this.

Related

Unique rows in join result

I have a tables of delas and curencies look like this
curecnies
id,code
pairs (the available pairs of curencies )
id to_sell to_buy
deals
id
user_id
pair_id
amount_to_sell
amount_to_buy
So I need to get all match deals which can execute , but I am can not get the unique matches.
Here is my sql query
select *
from deals as d1
join deals d2
on d1.sell_amount = d2.buy_amount and d1.buy_amount = d2.sell_amount
i am getting result look like this
id | user_id | pair_id | amount_to_buy | amount_to_sell | id | user_id | pair_id | amount_to_buy | amount_to_sell
1|2|1|1000|3000|2|1|2|3000|1000
2|1|2|3000|1000|1|2|1|1000|3000
You may try using a least/greatest trick here:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT
LEAST(d1.id, d2.id) AS d1_id,
GREATEST(d1.id, d2.id) AS d2_id
FROM deals AS d1
INNER JOIN deals d2
ON d1.sell_amount = d2.buy_amount AND
d1.buy_amount = d2.sell_amount
) d
INNER JOIN deals t1
ON d.d1_id = t1.id
INNER JOIN deals t2
ON d.d2_id = t2.id;
The basic idea here is that the subquery labelled d finds a single pair of matched deal IDs, using a least/greatest trick. Then, we join twice to the deals table again to bring in the full information for each member of that deal pair.

how to show 2 value and one values count from 3 table using mysql

I have 3 tables
Table1 (theoryquestion)
id | question | mark | technology
Table2 (mark)
mark | id
Table3 (technologies)
technology | id
I want to select count of question from corresponding mark and tech,
I have tried this
SELECT m.mark_name
, t.techname
, COUNT(q.question)
FROM question_mark m
JOIN theoryquestion q
on q.mark = m.mark_name
and q.technology = t.techname
JOIN technologies
You should use a proper on clause for join the table technologies
and use group by for trigger the aggregation function (count)
SELECT
question_mark.mark_name
,technologies.techname
,COUNT(theoryquestion.question)
FROM question_mark
INNER JOIN theoryquestion on theoryquestion.mark=question_mark.mark_name
INNER JOIN technologies theoryquestion.technology=technologies.techname
GROUP BY question_mark.mark_name ,technologies.techname
this worked for me..........
thank zzz
SELECT question_mark.mark_name,technologies.techname,COUNT(theoryquestion.question) FROM theoryquestion INNER JOIN question_mark on theoryquestion.mark=question_mark.mark_name INNER JOIN technologies on theoryquestion.technology=technologies.techname GROUP BY question_mark.mark_name ,technologies.techname

MySQL simple localization

Im trying to make some sort of localization in my DB.
For example I have 3 tables(img 1). Languages table contains different languages. Localization table has 3 fields: "id" - id of the string, 'language' - language of the string(id and language are my primary key), 'value' - localized string. tableOne has 'id', 'Col1' and 'Col2' - these fields contain IDs of the localizeable strings.
So after localizing I expect to get one of green tables instead of original(depending on a language parameter).
I've made it this way and it works, but I'd like to know is there any other better way to make it because now I have to create INNER JOIN block for each column, which must be localized. Im just scared that it will be very very slow.
I tried to create a temporary table to select all records of the required language and then i was doing the same. Inner joins, but searches should be performed only among the records of one language. But its not working because i still had to use multiple inner joins with that temp table which is impossible.
SELECT
`One`.`id` AS 'id',
`loc1`.`value` AS 'Col1',
`loc2`.`value` AS 'Col2'
FROM
`tableOne` AS `One`
INNER JOIN
`localization` AS `loc1`
ON `loc1`.`id` = `One.Col1`
AND `loc1`.`language` = 'en'
INNER JOIN
`localization` AS `loc2`
ON `loc2`.`id` = `One.Col2`
AND `loc2`.`language` = 'en'
img 1
If you want to reduce the number of JOINS needed, try displaying the values in rows instead of columns. You could do so like this:
SET #lang := 'en';
SELECT 1, tmp.value
FROM(
SELECT value
FROM localization
WHERE language = #lang AND id IN(543, 345)) tmp;
I first set a language parameter, and then I pull all values for that language from the localization table, using the ids inside an IN operator. You'll get results like this:
| 1 | one |
| 1 | two |
If you have to use the format given in the first table, try doing one inner join where you pull for the specific language and ids like this:
SELECT t1.id, t1.col1, t1.col2,
CASE WHEN l.id = t1.col1 THEN l.value ELSE null END AS col1Value,
CASE WHEN l.id = t1.col2 THEN l.value ELSE null END AS col2Value
FROM firstTable t1
JOIN localization l ON l.id IN (t1.col1, t1.col2) AND l.language = #lang;
Unfortunately, this won't give you the final solution, it will give you values like:
| 1 | 543 | 345 | one | null |
| 1 | 543 | 345 | null | two |
To wrap those into one column and remove nulls, just add MAX():
This will run a case statement for each column you have, but it will only have one JOIN and looks a little more manageable:
SELECT t1.id,
MAX(CASE WHEN l.id = t1.col1 THEN l.value ELSE null END) AS col1Value,
MAX(CASE WHEN l.id = t1.col2 THEN l.value ELSE null END) AS col2Value
FROM firstTable t1
JOIN localization l ON l.id IN (t1.col1, t1.col2) AND l.language = #lang
GROUP BY t1.id;
Here is an SQL Fiddle example. I don't think the case blocks will bog you down too much, but let me know how this preforms against your actual database.

Retrieve data from another table

I have a table like
tbl_scripts
script_unique_id | system_id | script_name
+-----------------------------------------+
12345 | 89784 | Demo
And another table goes as
tbl_allowed_group_ids
system_id | script_unique_id |allowed_group_id
+---------------------------------------------+
89784 12345 56987
So now what I want is the row from tbl_scripts with group_id only if the unique id is in allowed_group_id
What I tried is this but is nowhere close to it....I know this is completely wrong
SELECT script_name FROM tbl_scripts WHERE script_unique_id = allowed_group_id
You will want to JOIN the tables:
select *
from tbl_scripts s
left join tbl_allowed_group_ids g
on s.system_id = g.system_id
and s.script_unique_id = g.script_unique_id
See SQL Fiddle with Demo
If you need help learning join syntax, here is a great visual explanation of joins.
A LEFT JOIN will return all rows in the tbl_scripts table regardless of whether or not it has a matching row in the tbl_allowed_group_ids table. If you only want matching rows, then you can use an INNER JOIN
JOIN the two tables:
SELECT t1.script_name
FROM tbl_scripts t1
INNER JOIN tbl_allowed_group_ids t2 ON t1.script_unique_id = t2.allowed_group_id

How to left join or inner join a table itself

I have this data in a table, for instance,
id name parent parent_id
1 add self 100
2 manage null 100
3 add 10 200
4 manage null 200
5 add 20 300
6 manage null 300
How can I left join or inner join this table itself so I get this result below?
id name parent
2 manage self
4 manage 10
6 manage 20
As you can I that I just want to query the row with the keyword of 'manage' but I want the column parent's data in add's row as the as in manage's row in the result.
Is it possible?
EDIT:
the simplified version of my actual table - system,
system_id parent_id type function_name name main_parent make_accessible sort
31 30 left main Main NULL 0 1
32 31 left page_main_add Add self 0 1
33 31 left page_main_manage Manage NULL 0 2
my actual query and it is quite messy already...
SELECT
a.system_id,
a.main_parent,
b.name,
b.make_accessible,
b.sort
FROM system AS a
INNER JOIN -- self --
(
SELECT system_id, name, make_accessible, sort
FROM system AS s2
LEFT JOIN -- search --
(
SELECT system_id AS parent_id
FROM system AS s1
WHERE s1.function_name = 'page'
) AS s1
ON s1.parent_id = s2.parent_id
WHERE s2.parent_id = s1.parent_id
AND s2.system_id != s1.parent_id
ORDER BY s2.sort ASC
) b
ON b.system_id = a.parent_id
WHERE a.function_name LIKE '%manage%'
ORDER BY b.sort ASC
result I get currently,
system_id main_parent name make_accessible sort
33 NULL Main 0 1
but I am after this,
system_id main_parent name make_accessible sort
33 self Main 0 1
You just need to reference the table twice:
select t1.id, t1.name, t2.id, t2.name
from TableA t1
inner join TableA t2
on t1.parent_id = t2.Id
Replace inner with left join if you want to see roots in the list.
UPDATE:
I misread your question. It seems to me that you always have two rows, manage one and add one. To get to "Add" from manage:
select system.*, (select parent
from system s2
where s2.parent_id = system.parent_id
and s2.name = 'add')
AS parent
from system
where name = 'manage'
Or, you might split the table into two derived tables and join them by parent_id:
select *
from system
inner join
(
select * from system where name = 'add'
) s2
on system.parent_id = s2.parent_id
where system.name = 'manage'
This will allow you to use all the columns from s2.
Your data does not abide to a child-parent hierarchical structure. For example, your column parent holds the value 10, which is not the value of any id, so a child-parent association is not possible.
In other words, there's nothing that relates the record 2,manage,null to the record 1,add,self, or the record 4,manage,null to 3,add,10, as you intend to do in your query.
To represent hierarchical data, you usually need a table that has a foreign key referencing it's own primary key. So your column parent must reference the column id, then you can express a child-parent relationship between manage and add. Currently, that's not possible.
UPDATED: Joining by parent_id, try:
select m.id, m.name, a.parent
from myTable m
join myTable a on m.parent_id = a.parent_id and a.name = 'add'
where m.name = 'manage'
Change the inner join to a left join if there may not be a corresponding add row.