I have two tables I'm trying to join to produce a unique set of data for a third table, but having trouble doing this properly.
The left table has an id field, as well as a common join field (a).
The right table has the common join field (a), and another distinct field (b)
I'm trying to extract a result-set of id and b, where neither id nor b are duplicated.
I have an SQL fiddle set up: http://www.sqlfiddle.com/#!9/208de/3/0
The ideal results should be:
id | b
---+---
1 | 1
2 | 2
3 | 3
Each id and b value appears only once (it's only coincidence they match here, that can't be assumed always).
Thanks
What about a CTE along with a DISTINCT, Would that work?
WITH
cte1 (ID, B)
AS
(
SELECT DISTINCT Table1.ID
FROM Table1
WHERE Table1.ID IS NOT NULL
GROUP BY Table1.ID
)
SELECT DISTINCT
Table2.b
FROM Table2 AS sp
INNER JOIN cte1 AS ts
ON sp.b <> ts.ID
ORDER BY ts.ID DESC
Related
I have 3 different tables: table1, table2, table3
Table 1 contains all the different orders that were purchased
Table 2 contains the detail of every order (i mean, it contains a
column called ORDER_DETAIL and the number represent an item of
that order -a unique value)
Table 3 contains the workflow.. some numbers that were inside
ORDER_DETAIL from Table 2 will appear here because this item must be
approved to be delivered
I want to obtain all the different orders whose items did not appear in Table 3.
This picture explains everything:
This is my SQLFIDDLE: http://sqlfiddle.com/#!9/5bfc22/2
I did this query but i am not getting what i want:
select * from table1 kio
inner join table2 jio on kio.ORDER_NUMBER = jio.ORDER_NUMBER
where jio.CANCELLED = 0
and not exists (select 1 from table3 gio where jio.ORDER_DETAIL = gio.ORDER_DETAIL)
Also, how can i obtain those orders whose ORDER_DETAILs only appear on TABLE 2 AND those orders whose order_details appear in table 3 with PROCESSED = 1 and APPROVED = 1? All in the same query.
You can use aggregation: join table1 with table2, then left join table3, aggregate by order_number and filter on groups that have no match in table3.
select t1.id, t1.order_number
from table1 t1
inner join table2 t2 on t2.order_number = t1.order_number
left join table3 t3 on t3.order_detail = t2.order_detail
group by t1.id, t1.order_number
having count(t3.order_detail) = 0
In your DB Fiddle, this produces:
id order_number
3 46646
Also, how can i obtain those orders whose ORDER_DETAILs only appear on TABLE 2 AND those orders whose order_details appear in table 3 with PROCESSED = 1 and APPROVED = 1? All in the same query
For this, you can just add another pair of conditions in the having clause:
having
count(t3.order_detail) = 0
or (max(t3.processed) = 1 and max(t3.approved) = 1)
Yields:
id order_number
1 78945
3 46646
I want to obtain all the different orders whose items did not appear in Table 3.
This seems like a reasonable interpretation of the question, although you add more questions later.
If so, then you don't seem to need table1:
select t2.order_number
from table2 t2 left join
table3 t3
on t2.ORDER_DETAIL = t3.ORDER_DETAIL
group by t2.order_number
having count(t3.ORDER_DETAIL) = 0;
I have one table which has fields X,Y,Z,BAGID.
The BAGID is in the form of (12345-400) where 12345 is the user's id and 400 is the BAG's id.
I have another table which has fields A,B,C,USERID.
The USERID is in the form of 12345 which is same as the first part of BAGID.
So is it possible to join these two tables on the common USERID and get the fields USERID,X,Y,A,B?
Table 1:
X Y Z BAGID(userid+bagid)
1 2 4 12345-400
Table 2 :
A B C USERID
3 5 7 12345
I want the output as:
X Y A B USERID
1 2 3 5 12345
Is it possible to have a join these two tables?
select Table1.X, Table1.Y, Table2.A, Table2.B, Table2.USERID
from Table1
inner join Table2
on Table1.BAGID = Table2.USERID;
I know i cannot user BAGID and USERID as they are different. But is it possible for me to use the userid part of the BAGID of Table1 which is the same as USERID of Table2?
Any help would be appreciated.
You can use the SUBSTRING_INDEX to extract USERID out of BAGID:
select Table1.X, Table1.Y, Table2.A, Table2.B, Table2.USERID
from Table1
inner join Table2 on SUBSTRING_INDEX(Table1.BAGID, '-', 1) = Table2.USERID
This will work provided that there is only one '-' in BAGID.
Demo here
Sure, just join on LEFT(BAGID,5). Depending on the USERID DataType you may need to CAST it as well.
If the USERID portion of BAGIT is variable length you first need to find the length using INSTR(BAGID, '-')
If you're using t sql you can use the SUBSTRING ( expression ,start , length ) function to get only the first 5 characters of the bag id, and then join on that value. Ie
SELECT *
FROM table1
INNER JOIN table2 ON SUBSTRING(TABLE1.bagid, 0, 5) = table2.userid
If not using t sql, whatever you're using should have a similar substring function
You can inner join on substring of table1 column
Select Table1.X, Table1.Y, Table2.A, Table2.B, Table2.USERID
From Table1
Inner join Table2
ON SUBSTRING_INDEX(Table1.BAGID,'-',1) = Table2.USERID;
Is it possible/economical to perform a SELF JOIN of a table (for this example, my table called myTable has two columns pk and fk), and return a record if there is only one resulting record? I am thinking of something like the following, however, only_one_row() is a fictional function that would need to be replaced with something real:
SELECT fk
FROM myTable as t1
INNER JOIN myTable AS t2 ON t2.fk=t1.fk
WHERE t1.pk=1
AND only_one_row();
For instance, if myTable(id,fk) had the following records, only one record is produced, and I which to select the record:
1 1
2 1
3 2
However, if myTable(id,fk) had the following records, two '1' records are produced, and the select should not return any rows:
1 1
2 1
3 2
4 1
I could use PHP to do so, but would rather just use SQL if feasible.
Use a HAVING clause that counts the results.
SELECT fk
FROM myTable as t1
INNER JOIN myTable AS t2 ON t2.fk=t1.fk
WHERE t1.pk=1
HAVING COUNT(*) = 1
How about this:
SELECT fk
FROM myTable as t1
INNER JOIN myTable AS t2 ON t2.fk=t1.fk
WHERE t1.pk=1
GROUP BY fk
HAVING COUNT(fk) = 1
I'm doing an order on all fields of a table (depending on the user's choice), however one column of that table contains a category (stored as an abbreviation) and those abbreviations are defined in a second table. How can I sort by category name? Example of the table structures below:
Table 1
title | amount | category_abbreviation
Table 2 -> for category
category_name | category_abbreviation
Just join the tables and order on a field from the second table.
SELECT * from table1
INNER JOIN table2
ON table1.category_abbreviation = table2.category_abbreviation
ORDER BY table2.category_name
Create a view and run your query from that:
SELECT
Table1.title, Table1.amount, Table1.category_abbreviation, Table2.category_name
FROM
Table1
INNER JOIN Table2 ON Table1.category_abbreviation = Table2.category_abbreviation
and use that as your datasource. Or just use the SQL as your datasource, however you are doing it.
You don't have to select the Table2.category_name though if you didn't want to
try
SELECT t1.*
FROM Table_1 T1
JOIN Table_2 T2
ON T1.category_abbreviation=T2.category_abbreviation
ORDER BY T2.category_name
Using the following query
select *
from table1
left join table2 on table1.name = table2.name
table1 returns 16 rows and table2 returns 35 rows.
I was expecting the above query to return 16 rows because of the left join, but it is returning 35 rows. right join also returns 35 rows
Why is this happening and how do I get it to return 16 rows?
LEFT JOIN can return multiple copies of the data from table1, if the foreign key for a row in table 1 is referenced by multiple rows in table2.
If you want it to only return 16 rows, one for each table 1 row, and with a random data set for table 2, you can use just a plain GROUP BY:
select *
from table1
left join table2 on table1.name = table2.name
group by table1.name
GROUP BY aggregates rows based on a field, so this will collapse all the table1 duplicates into one row. Generally, you specify aggregate functions to explain how the rows should collapse (for example, for a number row, you could collapse it using SUM() so the one row would be the total). If you just want one random row though, don't specify any aggregate functions. MySQL will by default just choose one row (note that this is specific to MySQL, most databases will require you to specify aggregates when you group). The way it chooses it is not technically "random", but it is not necessarily predictable to you. I guess by "random" you really just mean "any row will do".
Let's assume you have the following tables:
tbl1:
|Name |
-------
|Name1|
|Name2|
tbl2:
|Name |Value |
--------------
|Name1|Value1|
|Name1|Value2|
|Name3|Value1|
For your LEFT JOIN you'll get:
|tbl1.Name|tbl2.Name|Value |
----------------------------
|Name1 | Name1 |Value1|
|Name1 | Name1 |Value2|
|Name2 | NULL | NULL |
So, LEFT JOIN means that all records from LEFT (first) table will be returned regardless of their presence in right table.
For your question you need to specify some specific fields instead of using "*" and add GROUP BY tbl1.Name - so your query will look like
select tbl1.Name, SOME_AGGREGATE_FUNCTION(tbl2.specific_field), ...
from table1
left join table2 on table1.name = table2.name
GROUP BY tbl1.Name
One way to use this is by using the power of SQL distinct.
select distinct tbl1.id, *
from table1 tbl1
left join table2 tbl2 on tbl2.name = tbl1.name
where
....................
Please not that I am also using aliasing.
If the name column is not unique in the tables then you may simply have duplicates on table2.
Try running:
select * from table2 where name not in (select name from table1);
If you get no results back then duplicates on the name column is the reason for the extra rows coming back.
Duplication may be reason. See example in the post
https://alexpetralia.com/posts/2017/7/19/more-dangerous-subtleties-of-joins-in-sql
if you want to join the single latest/earliest relative row from right table, you can limit the join data using min/max primary key and then limiting to 1 row using group Like this:
SELECT * FROM table1
LEFT JOIN (SELECT max(tbl2_primary_col), {table2.etc} FROM table2 GROUP BY name) AS tbl2
ON table1.name = tbl2.name
WHERE {condition_for_table1}
And remember don't use * for left join because it will disable min/max and always return first row.
As per your comment "A random row from table2, as long as name from table1 matches name from table2", you can use the following:
select table1.name, (select top 1 somecolumn from table2 where table2.name = table1.name)
from table1
Note that top 1 is not mysql but it is for SQL Server