How to remove duplicate/inverted rows from INNER JOIN - mysql

I am using SQL to pull from a table, I am also using an INNER JOIN to select to rows with linking values/columns, and appending them into one big row.
Table below:
| name | value | num |
| James | HEX124 | 1 |
| James | JEU836 | 4 |
I am now joining these two rows, into one row using this SQL:
SELECT a.name, a.value, a.num, b.name, b.value, b.num
FROM MY_TABLE a
INNER JOIN MY_TABLE b ON a.name = b.name //Inner joining where the name is the same
WHERE a.value <> b.value // where the values are NO the same
Result:
| a.name | a.value | a.num | b.name | b.value | b.num |
| James | HEX124 | 1 | James | JEU836 | 4 |
| James | JEU836 | 4 | James | HEX124 | 1 |
As you can see in the result, this is working, but it's returning every possible result, I want to only return one of these rows, as its duplicated/inverted them almost.
Maybe by returning only the first row WHERE a.name is a duplicate?
Desired Result:
| a.name | a.value | a.num | b.name | b.value | b.num |
| James | HEX124 | 1 | James | JEU836 | 4 |
Thank you

Simply change:
a.value <> b.value
to:
a.value < b.value
I would put the condition in the ON clause, like this:
SELECT a.name, a.value, a.num, b.name, b.value, b.num
FROM MY_TABLE a INNER JOIN
MY_TABLE b
ON a.name = b.name AND a.value < b.value;

Related

Get SUM another table off all rows in MySQL

I have database value, for example
table name: a_table
===================================
| userId | userName |
===================================
===================================
| abc | Alice |
| bcd | Rachel |
| efg | Raymond |
===================================
table name: b_transaction
=============================================
| transCode | userId | value |
=============================================
=============================================
| 1 | abc | 100 |
| 2 | abc | -200 |
| 3 | abc | 300 |
=============================================
My goal is, get sum of all data, if user dont have row in table transaction, they must be 0. But when I try this query
SELECT a.userId, a.userName, SUM(b.value)
FROM a_table a
LEFT JOIN b_transaction b ON a.userId = b.userId
The result just return 1 row
================================================
| userId | userName | value |
================================================
================================================
| abc | Alice | 200 |
================================================
How to achieve that?
Thaanks~
You could try grouping the results on the users over the summing of the transactions, like this?
SELECT a.userId, a.userName, SUM(b.value)
FROM a_table a
LEFT JOIN b_transaction b ON a.userId = b.userId
GROUP BY a.userId, a.userName
add group by:
SELECT a.userId, a.userName, IFNULL (SUM(b.value),0)
FROM a_table a
LEFT JOIN b_transaction b ON a.userId = b.userId
GROUP BY a.userId, a.userName
see the sqlfiddle
Using a simple group by statement in your SQL should create the desired result for example:
SELECT a.userId, a.userName, SUM(b.value)
FROM a_table a
LEFT JOIN b_transaction b ON a.userId = b.userId GROUP BY a.userId
You can use IFNULL to check if the result of the sum is null (that is the case if there is no reference for a row from a to b) or not, and then apply a default value :
SELECT a.userId, a.userName, IFNULL(SUM(b.value), 0) AS 'Sum'
FROM a_table a
LEFT JOIN b_transaction b ON a.userId = b.userId
GROUP BY a.userId, a.userName
This outputs :
| userId | userName | Sum |
| ------ | -------- | --- |
| abc | Alice | 200 |
| bcd | Rachel | 0 |
| efg | Raymond | 0 |

MS Access Full Outer Join using 2 fields?

I have 2 tables that I want to do a FULL OUTER JOIN on in MS Access.
Say I have Table A which looks like this:
A.ID | A.Value | A.DATE
--------+-----------+----------
1 | 30 | 05/2018
1 | 28 | 06/2018
1 | 26 | 07/2018
2 | 250 | 04/2018
2 | 252 | 05/2018
2 | 240 | 06/2018
And Table B which looks like this:
B.ID | B.FCST | B.OUTDATE
--------+-----------+-----------
1 | 35 | 06/2018
1 | 33 | 07/2018
1 | 30 | 08/2018
2 | 300 | 06/2018
2 | 280 | 07/2018
2 | 260 | 08/2018
And I need to perform Joins and Unions to achieve this:
A.ID | A.Value | A.DATE | B.FCST | B.OUTDATE
--------+-----------+---------+-----------+------------
1 | 30 | 05/2018 | - | -
1 | 28 | 06/2018 | 35 | 06/2018
1 | 26 | 07/2018 | 33 | 07/2018
1 | - | - | 30 | 08/2018
2 | 250 | 04/2018 | - | -
2 | 252 | 05/2018 | - | -
2 | 240 | 06/2018 | 300 | 06/2018
2 | - | - | 280 | 07/2018
2 | - | - | 260 | 08/2018
So I need to do an Inner Join with A.ID = B.ID, AND A.DATE = B.OUTDATE, and then somehow get "earlier" data from Table.A to "Sit on top" of the inner joined data, and the "later" data from Table.B to do the opposite. This is my attempt so far:
Select A.ID, A.Value, A.DATE, B.FCST, B.OUTDATE
FROM Table.A JOIN Table.B ON A.ID = B.ID AND A.DATE = B.OUTDATE
UNION ALL
Select A.ID, A.Value, A.DATE, B.FCST, B.OUTDATE
FROM Table.A LEFT JOIN Table.B ON A.ID = B.ID;
WHERE B.ID IS NULL
UNION ALL
Select A.ID, A.Value, A.DATE, B.FCST, B.OUTDATE
FROM Table.A RIGHT JOIN Table.B ON A.ID = B.ID
WHERE A.ID IS NULL
ORDER BY A.ID ASC;
But I've missed the mark it appears. I'm getting duplicate lines, and it just looks like an Inner Join. I will gladly take any advice as to help get this right.
I would suggest a union of two left joins to give the same result as full outer, and finally with a touch of sorting to yield the desired ordering:
select c.* from
(
select a.id, a.value, a.date, b.fcst, b.outdate
from a left join b on a.id = b.id and a.date = b.outdate
union
select b.id, a.value, a.date, b.fcst, b.outdate
from b left join a on a.id = b.id and a.date = b.outdate
) c
order by c.id, nz(c.date, c.outdate)

MySql. How can i get count from 2 tables

I have 2 tables, TableA and TableB
TableA
IdA | Date | Description
--- | ---------- | -----------
1 | 2017-01-01 | Sometext1
2 | 2017-01-01 | Sometext2
3 | 2017-01-02 | Sometext3
4 | 2017-01-03 | Sometext4
TableB
IdB | IdA | Type
--- | --- | ----
1 | 1 | A
2 | 1 | A
3 | 2 | A
4 | 2 | A
5 | 2 | B
6 | 3 | B
7 | 4 | A
How can I get value like this :
Count(IdA) | Type
---------- | ----
3 | A
I have tried to code using INNER or LEFT JOIN like
SELECT COUNT(tablea.IdA), tableb.Type
FROM tablea INNER JOIN tableb
ON tablea.IdA=tableb.IdA
WHERE tableb.Type='A'
But it always get me like this
Count(IdA) | Type
---------- | ----
5 | A
I just want to count TableA row with WHERE clause from TableB.
Is it possible to do something like that?
You probably want COUNT(DISTINCT col).
Try this:
SELECT
COUNT(DISTINCT a.IdA), b.Type
FROM
tablea a
INNER JOIN
tableb b ON a.IdA = b.IdA
WHERE
b.Type = 'A'
GROUP BY b.type
Yes, you need distinct column ids (but here's an answer using alias)
SELECT COUNT(distinct A.IdA), B.Type
FROM tablea A
INNER JOIN tableb B ON (A.IdA = B.IdA)
WHERE B.Type = 'A'
And you don't even need to put an ON clause if you join by the same column name so, making the sql even shorter.
SELECT COUNT(distinct A.IdA), B.Type
FROM tablea A
INNER JOIN tableb B
WHERE B.Type = 'A'

Select distinct ordered pairs from table join grouped by event's most recent date

Following the post Select distinct ordered pair from table join
How can I select the most recent John's joined rows grouped by ordered pair, regardless the order (e.g. John -> Jane or Jane -> John)?
First table:
table_a
+-----------+--------------+-------------------+
| id | name | created_at |
+-----------+--------------+-------------------+
| 1 | John |2016-08-26 15:40:21|
+-----------+--------------+-------------------+
| 2 | Jane |2016-08-26 15:37:21|
+-----------+--------------+ ------------------+
| 3 | Jane |2016-08-26 15:38:21|
+-----------+--------------+-------------------+
| 4 | Tara |2016-08-26 15:39:21|
+-----------+--------------+-------------------+
Second Table:
table_b
+-----------+-------------------+-------------+-------------+
| id | id_table_a | name | message |
+-----------+-------------------+-------------+-------------+
| 1 | 1 | Jane | Test 1 |
+-----------+-------------------+-------------+-------------+
| 2 | 2 | John | Test 2 |
+-----------+-------------------+-------------+-------------+
| 3 | 3 | Sammy | Test 3 |
+-----------+-------------------+-------------+-------------+
| 4 | 4 | John | Test 4 |
+-----------+-------------------+-------------+-------------+
One possible result
+-----------+-------------+-------------+-------------+-------------------+
| id | name_a | name_b | message | created_at |
+-----------+-------------+-------------+-------------+-------------------+
| 1 | John | Jane | Test 1 |2016-08-26 15:40:21|
+-----------+-------------+-------------+-------------+-------------------+
| 4 | Tara | John | Test 4 |2016-08-26 15:39:21|
+-----------+-------------+-------------+-------------+-------------------+
sqlfiddle
Thanks a lot!
Try this:
(select a.id, a.name, b.name, b.message, a.created_at from a left join b on a.id=b.aid where a.name='John' order by a.created_at desc limit 1)
union all
(select a.id, a.name, b.name, b.message, a.created_at from a left join b on a.id=b.aid where b.name='John' order by a.created_at desc limit 1)
This gets a bit messy. Here's an option using user-defined variables to establish a row_number within each group of results and then filtering by row number = 1:
select *
from (
select *,
#rn := if(#prev_name_a = name_a and #prev_name_b = name_b, #rn+1,
if(#prev_name_a:=name_a,1,
if(#prev_name_b:=name_b, 1, 1)
)
) rn
from (
select least(a.name, b.name) as name_a,
greatest(a.name, b.name) as name_b,
a.created_at,
a.id,
b.message
from table_a a
join table_b b on a.id = b.id_table_a
) t cross join (select #rn:=0, #prev_name_a:=null, #prev_name_b:=null) t1
order by name_a, name_b, created_at desc
) t
where 'John' in (name_a, name_b) and rn = 1
SQL Fiddle Demo

MSQL select regardless of distinct or not distinct (count greater than zero)

I've found many ways to show only distinct results, but how would I select both the distinct and the non distinct together? Consider these tables:
A
---------------------------------
| id | col1 | col2 |
---------------------------------
| 1 | aa | dd |
---------------------------------
| 1 | bb | ee |
---------------------------------
| 2 | cc | ff |
---------------------------------
B
---------------------------------
| id | col1 | col2 |
---------------------------------
| 1 | a | d |
---------------------------------
| 2 | b | e |
---------------------------------
| 3 | c | f |
---------------------------------
C
---------------------------------
| id | col1 | col2 |
---------------------------------
| 1 | x | 1a |
---------------------------------
| 2 | y | 2b |
---------------------------------
| 3 | x | 3c |
---------------------------------
A user supplies to me an id and a list of columns, say id = 1 and columns = (a.col1, b.col1, and c.col2). How would I construct a query to give me all column information where the id matches, regardless of how many times the id appears?
My current query is:
SELECT a.col1, b.col1, c.col2
FROM a
LEFT JOIN b
ON b.id = a.id
LEFT JOIN c
ON c.id = b.id
WHERE a.id = 1
The problem is that this only gives me one result from table A when I'd like to get both results (or all results from any table that happens to have repeating ids that match). Note: In table A, the columns id and col1 together make up the primary key which is why I have repeating ids.
Suggestions?
Thanks!
In the data in the question, there is no repeating id in table A. The query should be returning only one row from A, then.
However, your query has an error. The second join should be back to the first table, not the second:
SELECT a.col1, b.col1, c.col2
FROM a
LEFT JOIN b
ON b.id = a.id
LEFT JOIN c
ON c.id = a.id
WHERE a.id = 1
You had c.id = b.id and b.id could be NULL if there is no match in that table.
Also, from your description, I wonder if a union would be the best approach:
select a.col1, 'a'
from a
where id = 1
union all
select b.col1, 'b'
from b
where id = 1
union all
select c.col2, 'c'
from c
where id = 1