SQL Distinct based on different colum - mysql

I have problem to distinct values on column based on other column. The case study is:
Table: List
well | wbore | op|
------------------
wella|wbore_a|op_a|
wella|wbore_a|op_b|
wella|wbore_a|op_b|
wella|wbore_b|op_c|
wella|wbore_b|op_c|
wellb|wbore_g|op_t|
wellb|wbore_g|op_t|
wellb|wbore_h|op_k|
So, I want the output to be appear in different field/column like:
well | total_wbore | total_op
----------------------------
wella | 2 | 3
---------------------------
wellb | 2 | 2
the real study case come from different table but to simplify it I just assume this case happened in 1 table.
The sql query that I tried:
SELECT well.well_name, wellbore.wellbore_name, operation.operation_name, COUNT(*)
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name,wellbore.wellbore_name
HAVING COUNT(*) > 1
But this query is to calculate the duplicate row which not meet the requirement. Anyone can help?

you need to use count distinct
SELECT
count(distinct wellbore.wellbore_name) as total_wbore
count(distinct operation.operation_name) as total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid

Final query:
SELECT
well.well_name,
COUNT(DISTINCT wellbore.wellbore_name) AS total_wbore,
COUNT(DISTINCT operation.operation_name) AS total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name

Related

Static SQL query replace to dynamic column

I have following query:
http://www.sqlfiddle.com/#!9/752e34/3
This query use SELECT in SELECT queries.
"SELECT a.*
,(SELECT s.value FROM tbl_scd AS s WHERE s.tag_id = 1 AND s.main_id = a.id ORDER BY s.date_time DESC LIMIT 1) AS title
,(SELECT s.value FROM tbl_scd AS s WHERE s.tag_id = 2 AND s.main_id = a.id ORDER BY s.date_time DESC LIMIT 1) AS alt
FROM tbl_main AS a
WHERE 1;"
Now I'm looking for a solution to add a new row into tbl_tag without change the above query (that the SELECT in SELECT part will be dynamic) to get a reference to tbl_tag
To get this:
+----+---------------+-----------+-----------+--------------+
| id | date | title | alt | new_column |
+----+---------------+-----------+-----------+--------------+
| 1 | 2018-10-10 | test1-1 | test1-3 | NULL |
| 2 | 2018-10-11 | test2-1 | test2-1 | NULL |
+----+---------------+-----------+-----------+--------------+
It would be great to get an idea or help.
Thanks
Your last comment on your question about using JOIN makes it clearer to me (I think) what you are after. JOINs will definitely help you a lot here, in place of the rather cumbersome query you are currently using.
Try this:
SELECT
tbl_main.date,
tblA.value AS title,
tblB.value AS alt
FROM
tbl_main
INNER JOIN (SELECT main_id, tag_id, value
FROM tbl_scd
INNER JOIN tbl_tag ON (tbl_scd.tag_id = tbl_tag.id)
WHERE tbl_tag.name = 'title') tblA
ON (tbl_main.id = tblA.main_id)
INNER JOIN (SELECT main_id, tag_id, value
FROM tbl_scd
INNER JOIN tbl_tag ON (tbl_scd.tag_id = tbl_tag.id)
WHERE tbl_tag.name = 'alt') tblB
ON (tbl_main.id = tblB.main_id);
I think this will get you much closer to a general solution to what it looks like you are trying to achieve, or at least point you in a good direction with using JOINs.
I also think you might benefit from re-thinking your database design, because this kind of pivoting rows from one table into columns in a query output can be an indicator that the data might be better off structured differently.
In any case, I hope this helps.

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

find elements with same charateristics

Supposing I have a table where a material has asignments of different characteristics. A material can have one or more charateristics. Then I would like to find to a certain material similar materials, that means at least 2 characteristics should match. In this example I should find material C when I compare with A and D should find B. Is there any solution in SQL?
material | character
----------------------
A | 2
A | 5
B | 1
B | 3
B | 4
C | 2
C | 5
D | 3
D | 1
This is an Entity-Attribute-Value table, and it notoriously painful to search. (In this case, the value is implied as being TRUE for has this attribute.)
It involves comparing everything against everything, grouping the results, and checking if the groups match. Virtually no use of indexes or intelligence of any kind.
SELECT
material_a.material AS material_a,
material_b.material AS material_b
FROM
material AS material_a
LEFT JOIN
material AS material_b
ON material_a.character = material_b.character
AND material_a.material <> material_b.material
GROUP BY
material_a.material,
material_b.material
HAVING
0 = MAX(CASE WHEN material_b.character IS NULL THEN 1 ELSE 0 END)
This gives every material_b that has all of the characteristics that material_a has.
- The HAVING clause will check that every 0 of material a's characteristics are missing from material b.
Changing to an INNER JOIN and changing the HAVING CLAUSE will get the share at least two materials.
SELECT
material_a.material AS material_a,
material_b.material AS material_b
FROM
material AS material_a
INNER JOIN
material AS material_b
ON material_a.character = material_b.character
AND material_a.material <> material_b.material
GROUP BY
material_a.material,
material_b.material
HAVING
COUNT(*) >= 2
Either way, you still are joining the whole table against the whole table, then filtering out the failures. With 100 materials, that's 9,900 material-material comparison. Imagine when you have 1000 materials and have 999,000 comparisons. Or 1million materials...
You could use something like the following grouped table to determine all items with more than 2 similar characteristics
SELECT
material = t1.material
, similarMaterial = t2.material
FROM
tableName t1
INNER JOIN tableName t2 ON t1.character = t2.character AND NOT(t1.material = t2.material)
GROUP BY material
HAVING
COUNT(*) >= 2
Yes, you can find all paired of similar materials with SQL similar to this:
SELECT c1.material, c2.material, COUNT(*) as characterCount
FROM charateristics c1
CROSS JOIN charateristics c2
WHERE c1.material > c2.material AND c1.character = c2.character
GROUP BY c1.material, c2.material
HAVING characterCount >= 2;
This would give you the results based on a material input:
SELECT b.material
FROM table1 a
INNER JOIN table1 b
ON a.character = b.character AND a.material <> b.material
WHERE a.material = 'A' -- Your input
GROUP BY b.material
HAVING COUNT(*) > 1;
sqlfiddle demo
Or do this to give you the pairs:
SELECT a.material as LEFT_MATERIAL ,b.material AS RIGHT_MATERIAL
FROM table1 a
INNER JOIN table1 b ON a.character = b.character AND a.material <> b.material
GROUP BY a.material,b.material
HAVING COUNT(*) > 1;
sqlfiddle demo

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