MySQL unmatched records with additional fields - mysql

I have the following query which works just fine:
SELECT lastname, firstname, date, complete
FROM table1
WHERE complete NOT IN (SELECT complete FROM table2)
ORDER BY lastname
I'm being asked to provide information from columns that are in table2 but NOT in table1. Like so:
SELECT t1.lastname, t1.firstname, t1.date, t1.complete, t2.newdata
FROM table1 t1, table2 t2
WHERE t1.complete NOT IN (SELECT t2.complete FROM table2)
ORDER BY lastname
However, either this does not work or it somehow got caught in a loop because I had to kill the process after 2 hours.
Is there a way to include data from the table which is being compared (table2)?

I think you question is a little too broad, what is your requirements for t2.newdata?
What you are trying to do doesn't appear to me like it would ever work. You want to get newData from t2, where t2.complete != t1.complete, so how do you know which values of t2 to use? And how do you know which rows to match them with?
I think and I will await a comment from you to know for sure, is that you want all of that information from table 1, and only the information from table 2 when it matches. This describes an outer join.
Try something like this:
SELECT t1.lastName, t1.firstName, t1.date, t1.complete, t2.newData
FROM table1 t1
LEFT JOIN table2 t2 ON t2.complete = t1.complete
ORDER BY t1.lastName;
As I said, this will select all rows from table1, and will put a value in the newData column wherever the complete field has a matching row in table2. If there is not a matching row, the value is null.
See this SQL Fiddle, as well as the above outer join link for more info.

Try this:
SELECT t1.lastname, t1.firstname, t1.date, t1.complete, t2.newdata
FROM table1 t1
join table2 t2 on t2.id=t1.id and t1.complete !=t2.complete
ORDER BY t1.lastname

Related

How to use Concat() & Substring in one query?

For question purposes I will use minimal data for my examples.
I have a table called table1 and a column named test that looks like this:
test
5012
I am able to add an extra zero behind before the result of column test using this query:
SELECT CONCAT('0',test) as x from table1
this is the result of the query:
results table: table1
x
05012
Now I have another table called table2 looking like this:
test test2
05012 1
My question is, how do I join the two tables together based on that query above and concat the table1 with column test2 from table2? Making sure the first 4 characters of both columns test from both tables match together?
This is how table 1 should look like:
Afterquery
050121
I am curious why you wouldn't simply use table2?
select concat(t2.test, t2.test2) as afterquery
from table2 t2;
table1 doesn't seem to play a role.
If you want values in table2 filtered by table1, you can use exists:
select concat(t2.test, t2.test2) as afterquery
from table2 t2
where exists (select 1
from table1 t1
where t2.test = concat('0', t1.test)
);
You can express this as a join:
select concat(t2.test, t2.test2) as afterquery
from table2 t2 join
table1 t1
on t2.test = concat('0', t1.test);
This is useful if you want columns from both tables -- but that is not necessary to answer the question. On the other hand, this runs the risk of duplication if there are multiple matches.
I think that this should be the solution. You need to use concat in the join between table1 and table2
SELECT CONCAT('0', table1.test, table2.test2) AS Afterquery
FROM table1
INNER JOIN table2
ON CONCAT('0',table1.test) = table2.test
Slightly different approach with a sub-query:
select concat(concat_test, test2) test_results
from
(select concat('0', test) concat_test from table1) table_alias
join
table2 on substring(concat_test,1,4) = substring(test,1,4);

Is there a more efficient way using mysql to get a list for a given column in an sql result?

I have a query that rows of a table each containing an id.
For each id I want to get multiple values from another table.
The way I would do this is make the first query, then loop through the result making a query for each id.
This could mean making a thousand queries, is there a way I could do this in 1 query.
I think you want group_concat(). Something like this:
select t1.id, group_concat(t2.othercol)
from table1 t1 join
table2 t2
on t1.id = t2.id
group by t1.id;
Or perhaps you just want in:
select t2.*
from table2 t2
where t2.id in (select t1.id from table1 t1);

Inner Join SQL Syntax

I've never done an inner join SQL statement before, so I don't even know if this is the right thing to use, but here's my situation.
Table 1 Columns: id, course_id, unit, lesson
Table 2 Columns: id, course_id
Ultimately, I want to count the number of id's in each unit in Table 1 that are also in Table 2.
So, even though it doesn't work, maybe something like....
$sql = "SELECT table1.unit, COUNT( id ) as count, table2.id, FROM table1, table2, WHERE course_id=$im_course_id GROUP BY unit";
I'm sure the syntax of what I'm wanting to do is a complete fail. Any ideas on fixing it?
SELECT unit, COUNT( t1.id ) as count
FROM table1 as t1 inner JOIN table2 as t2
ON t1.id = t2.id
GROUP BY unit
hope this helps.
If I understand what you want (maybe you could post an example input and output?):
SELECT unit, COUNT( id ) as count
FROM table1 as t1 JOIN table2 as t2
ON t1.id = t2.id
GROUP BY unit
Okay, so there are a few things going on here. First off, commas as joins are deprecated so they may not even be supported (depending on what you are using). You should probably switch to explicitly writing inner join
Now, whenever you have any sort of join, you also need on. You need to tell sql how it should match these two tables up. The on should come right after the join, like this:
Select *
From table1 inner join table2
on table1.id = table2.id
and table1.name = table2.name
You can join on as many things as you need by using and. This means that if the primary key of one table is several columns, you can easily create a one-to-one match between tables.
Lastly, you may be having issues because of other general syntax errors in your query. A comma is used to separate different pieces of information. So in your query,
SELECT table1.unit, COUNT( id ) as count, table2.id, FROM ...
The comma at the end of the select shouldn't be there. Instead this should read
SELECT table1.unit, COUNT( id ) as count, table2.id FROM ...
This is subtle, but the sql query cannot run with the extra comma.
Another issue is with the COUNT( id ) that you have. Sql doesn't know which id to count since table1 and table2 both have ids. So, you should use either count(table1.id) or count(table2.id)

SQL query to get only the latest value by Date

I have the following two tables:
Table1 {T1ID, Name}
Table2 {T2ID, T1ID, Date, Value}
Date is of type DATE.
and I am looking for a SQL query to fetch only the latest value (by Date) for each T1ID for which the Name matches a specific string.
SELECT`Table2`.`T1ID`,
`Table2`.`Value`,
`Table2`.`Date`,
`Table1`.`Name`,
FROM `Table1`
INNER JOIN `Table2` ON `Table2`.`T1ID` = `Table1`.`T1ID`
WHERE `Table1`.`Name` LIKE 'Smith'
but this returns the value for several dates for the same T1ID.
How do I get only the latest value by Date?
Edit:
I am using MySQL 5.5.8
If I've understodd the question correctly:
Assuming MySQL:
SELECT`Table2`.`T1ID`,
`Table2`.`Value`,
`Table2`.`Date`,
`Table1`.`Name`
FROM `Table1`
INNER JOIN `Table2` ON `Table2`.`T1ID` = `Table1`.`ID`,
(SELECT T1ID, MAX(Date) AS 'Date' FROM Table2 GROUP BY T1ID) Table3
WHERE
`Table3`.`T1ID` = `Table2`.`T1ID`
AND
`Table3`.`Date` = `Table2`.`Date`
AND
`Table1`.`Name` LIKE 'Smith'
EDIT: Updated the code to bring back the correct result set. Removed MSSQL answer as it wasn't relevant
You have two options.
select t1.t1id, max(t1.Name) Name, max(t2.date) Date,
(select Value from table2 t22
where t22.date = max(t2.date) and t22.t1id = t2.t1id) Value
from table1 t1 left join table2 t2 on t1.t1id = t2.t1id
where Name like '%Smith%'
group by t2.t1id order by 2
OR
select mx.t1id, mx.Name, mx.Date, t2.Value
from
(
select t1.t1id, max(t1.Name) Name, max(t2.date) Date
from table1 t1 left join table2 t2 on t1.t1id = t2.t1id
where Name like '%Smith%'
group by t2.t1id
) mx left join table2 t2 on (t2.t1id = mx.t1id and t2.date = mx.date)
order by 2
Both will produce the same result. The first one takes less code but you might have performance issues with a huge set of data. The second one takes a little more code, but it is also a little more optimized. Notes on the JOIN option:
If you go LEFT JOIN (as the example shows), items in Table1 with no correspondent records on Table2 will be displayed in the result, but the values in columns Date and Value will be NULL
If you go INNER JOIN, items in Table1 with no correspondent records on Table2 will not be displayed.
EDIT
I missed one of the requirements, which was the Name matching a specific string. The code is now updated. The '%' acts like a wildcard, so it will match names like 'Will Smith' and 'Wail Smithers'. If you want a exact match, remove the wildcards ('%').
Add this to your SQL:
ORDER BY 'Date' DESC LIMIT 1

SQL: How can we make a table1 JOIN table2 ON a table given in a field in table1?

Imagine I have table1 which has a column named 'table_name'. I use table1.table_name to store the name of another table in the database. The referenceable tables would all have a field 'target_id.
Is is possible to use table_name in a JOIN statement?
For example:
SELECT t1.*, t2.* FROM table1 AS t1
JOIN table1.table_name AS t2 ON t1.table1_id = t2.target_id
The obvious solution is to use the script (C++ in my case) to get the table name first, and construct a SQL query from it. The question is: can we bypass the script and do this directly in SQL (MySQL)?
Edit: What is dynamic SQL?
The only chance you have is to do 2 SQL statements:
select the tablename you need
use this table-name to dynamically build the secound query to get the data you need - what you want isn't possible to do with SQL directly (and it sounds like you've designed your database wrong in some way - but that's hard to say without knowing what's the goal of it).
I know I'm late to the party, but I wanted to offer a different solution. I see this sort of thing a lot in audit tables. The column table_name would refer to "what table was changed" and table1_id would refer to the ID of the row that changed in that table. In this case, the audit table is pointing back to many different tables that don't normally get joined.
Here goes:
SELECT t1.*, t2.*, t3.*, t4.*, t5.*
FROM table1 AS t1
left JOIN table2 AS t2
ON t1.table1_id = t2.target_id
and t1.table_name = 'table2'
left JOIN table3 AS t3
ON t1.table1_id = t3.target_id
and t1.table_name = 'table3'
left JOIN table4 AS t4
ON t1.table1_id = t4.target_id
and t1.table_name = 'table4'
left JOIN table5 AS t5
ON t1.table1_id = t5.target_id
and t1.table_name = 'table5'
Of course, the main drawback is that each table that can be possibly referenced needs to be explicitly included in the SQL command.
You can get more elegant output using this as your select list:
SELECT
t1.*,
coalesce(t2.fieldA, t3.fieldA, t4.fieldA, t5.fieldA) as fieldA,
coalesce(t2.fieldB, t3.fieldB, t4.fieldB, t5.fieldB) as fieldB
etc