Join data from two tables and top from table 2 - sql

i have this tables:
Table1:
id Name
1 Example1
2 Example2
Table2:
id Date..............
1 5.2.2014........
1 6.2.2014.........
1 6.2.2014........
2 16.1.2014.......
2 17.1.2014.......
And I need take id and Name from table1 and join table1.id = table2.id and from table2 take only top 1 row...
Example:
id Name Date
1 Example1 5.2.2014
2 Example2 16.1.2014
It is possible?

You can use row_number() to filter out all but the latest row per id:
select *
from (
select row_number() over (partition by id order by Date desc) as rn
, *
from Table2
) as t2
join Table1 as t1
on t1.id = t2.id
where t2.rn = 1 -- Only latest row

Well, a simple attempt would be
SELECT t1.*,
(SELECT TOP 1 t2.Date FROM Table2 t2 WHERE t2.ID = t1.ID t2.Date) t2Date
FROM Table1 t1
If you were using SQL Server, you could use ROW_NUMBER
Something like
;WITH Vals AS (
SELECT t1.ID,
t1.Name,
t2.Date,
ROW_NUMBER() OVER(PARTITION BY t1.ID ORDER BY t2.Date) RowID
FROm Table1 t1 LEFT JOIN
Table2 t2 ON t1.ID
)
SELECT *
FROM Vals
WHERE RowID = 1

Select t1.id, t1.name , MIN(t2.date)
From table1 t1
Inner Join table2 t2
On t1.id=t2.id
Group By t1.id, t1.name

Related

Displaying records only when there are more than same three values

Is there a way to display only records where one email corresponds to more than 3 names?
I have tried the code below, but it does not return anything.
SELECT
t1.Name, t2.Email
FROM
Table1 t1
JOIN Table2 t2 on t1.ID=t2.PersonID
GROUP BY
t1.Name, t2.Email
HAVING COUNT(t2.Email) > 3
If your version supports window function then you can do :
select t.*
from (select t1.name, t2.email,
count(t2.email) over (partition by t1.name) as cnt
from t1 inner join
t2
on t2.personid = t1.id
) t
where cnt > 3;
I think you want:
SELECT t1.Name, GROUP_CONCAT(t2.Email)
FROM Table1 t1 JOIN
Table2 t2
ON t1.ID = t2.PersonID
GROUP BY t1.Name
HAVING COUNT(t2.Email) > 3;
The big change is to the GROUP BY -- this does not have EMAIL. You seem to want the emails returns on each row, so this concatenates them together.
EDIT:
In SQL Server, you would use string_agg():
SELECT t1.Name, STRING_AGG(t2.Email, ',')
FROM Table1 t1 JOIN
Table2 t2
ON t1.ID = t2.PersonID
GROUP BY t1.Name
HAVING COUNT(t2.Email) > 3;
Or, if you want individual rows:
SELECT n.*
FROM (SELECT t1.Name, t2.Email,
COUNT(*) OVER (PARTITION BY t1.Name) as cnt
FROM Table1 t1 JOIN
Table2 t2
ON t1.ID = t2.PersonID
) n
WHERE cnt > 3
ORDER BY Name;

where column in from another select results with limit (mysql/mariadb)

when i run this query returns all rows that their id exist in select from table2
SELECT * FROM table1 WHERE id in (
SELECT id FROM table2 where name ='aaa'
)
but when i add limit or between to second select :
SELECT * FROM table1 WHERE id in (
SELECT id FROM table2 where name ='aaa' limit 4
)
returns this error :
This version of MariaDB doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
You are using LIMIT without an ORDER BY. This is generally not recommended because that returns an arbitrary set of rows -- and those can change from one execution to another.
You can convert this to a JOIN -- fortunately. If id is not duplicated in table2:
SELECT t1.*
FROM table1 t1 JOIN
(SELECT t2.id
FROM table2 t2
WHERE t2.name = 'aaa'
LIMIT 4
) t2
USING (id);
If id can be duplicated in table2, then:
SELECT t1.*
FROM table1 t1 JOIN
(SELECT DISTINCT t2.id
FROM table2 t2
WHERE t2.name = 'aaa'
LIMIT 4
) t2
USING (id);
Another fun way uses LIMIT:
SELECT t1.*
FROM table1 t1
WHERE id <= ANY (SELECT t2.id
FROM table2
WHERE t2.name = 'aaa'
ORDER BY t2.id
LIMIT 1 OFFSET 3
);
LIMIT is allowed in a scalar subquery.
You can use an analytic function such as ROW_NUMBER() in order to return one row from the subquery. I suppose, this way no problem would occur like raising too many rows issue :
SELECT * FROM
(
SELECT t1.*,
ROW_NUMBER() OVER (ORDER BY t2.id DESC) AS rn
FROM table1 t1
JOIN table2 t2 ON t2.id = t1.id
WHERE t2.name ='aaa'
) t
WHERE rn = 1
P.S.: Btw, id columns are expected to be primary keys of your tables, aren't they ?
Update ( depending on your need in the comment ) Consider using :
SELECT * FROM
(
SELECT j.*,
ROW_NUMBER() OVER (ORDER BY j.id DESC) AS rn2
FROM job_forum j
CROSS JOIN
( SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY t2.id ORDER BY t2.id DESC) AS rn1
FROM table2 t2
WHERE t2.name ='aaa'
AND t2.id = j.id ) t2
WHERE rn1 = 1
) jj
WHERE rn2 <= 10

How to get Top 1 with Sort from Join

Instead of doing something like this:
SELECT
t1.*,
(SELECT TOP 1 t2.Name FROM Table2 t2 Order By t2.Number) Val1
FROM Table1 t1
How would it be done with a Join instead?
SELECT
t1.*,
TOP 1 t2.Name
FROM Table1 t1
JOIN Table2 t2 Order By t2.Number
or is it even possible?
select top 1 * from (SELECT t1.*, t2.Number num FROM table1 t1 JOIN table2 t2 on t1.commoncolumn=t2.commoncolumn ) t order by t.num
Try this (id is the join field)
with Table2Data as
(
SELECT Id , Name ,row_number() over(partition by Id order by number) rowNumber FROM Table2
)
select t1.* ,t2.name from table1 t1
inner join Table2Data t2 on t1.Id=t2.Id and t2.rowNumber=1
The following accomplishes the same thing.
SELECT t1.*, MIN(t2.Name) OVER() val1 FROM Table1 INNER JOIN Table2 t2 on t1.id = t2.id
It can be done with a CROSS APPLY. Assuming Id is the common field:
SELECT t1.*
, t3.Name
FROM Table1 t1
CROSS APPLY (
SELECT TOP 1 t2.Name
FROM Table2 t2
WHERE t1.Id = t2.Id
ORDER BY t2.Number
) t3

SQL Query with conditional JOIN

The scenario:
Table1
CatId|Name|Description
Table2
ItId|Title|Date|CatId (foreign key)
I want to return all rows from Table1 and Title,Date from Table2, where
The returned from Table 2 must be the Latest one by the date column.
(in second table there many items with same CatId and I need just the latest)
I have 2 queries but can't merge them together:
Query 1:
SELECT Table1.Name, Table1.Description,
Table2.Title, Table2.Date
FROM
Table1 LEFT JOIN Table2 ON Table1.CatId=Table2.CatId
Query2:
SELECT TOP 1 Table2.Title, Table2.Date
FROM
Table2
WHERE
Table2.CatId = #inputParam
ORDER BY Table2.Date DESC
You can use a UNION, but you'll need to make the columns match up:
OK, after rereading the question, I understand what you're trying to do.
This should do the trick:
SELECT Table1.Name, Table1.Description,
T2.Title, T2.Date
FROM
Table1
LEFT JOIN (
SELECT CatId, Title, Date, ROW_NUMBER() over (ORDER BY CatId, Date DESC) - RANK() over (ORDER BY CatID) as Num
FROM Table2) T2 on T2.CatId = Table1.CatId AND T2.Num = 0
Sounds like you're talking about a groupwise maximum (newest row in Table2 for each matching row in Table1), in which case, the easiest way is use ROW_NUMBER:
WITH CTE AS
(
SELECT
t1.Name, t1.Description, t2.Title, t2.Date,
ROW_NUMBER() OVER (PARTITION BY t1.CatId ORDER BY t2.Date DESC) AS Seq
FROM Table1 t1
LEFT JOIN Table2 t2
ON t2.CatId = t1.CatId
)
SELECT *
FROM CTE
WHERE Seq = 1
OR Date IS NULL
Shouldn't this work?
SELECT Table1.Name, Table1.Description,
T2.Title, T2.Date
FROM
Table1 LEFT JOIN (
SELECT TOP 1 Table2.CatId Table2.Title, Table2.Date
FROM
Table2
WHERE
Table2.CatId = Table1.catId
ORDER BY Table2.Date DESC
) T2
ON Table1.CatId=T2.CatId

Merge and add values from two tables

Is it possible to craft a query that adds values within two tables:
For example, say you have two tables
id value
-- -----
a 1
c 2
d 3
f 4
g 5
and
id value
-- -----
a 1
b 2
c 3
d 4
e 5
Then when you 'add' the two tables you would get the result where the id's match. So, a=1+1=2, and simply the same result where they don't. So the query would return:
id value
-- -----
a 2
b 2
c 5
d 7
e 5
f 4
g 5
maybe something like
select coalesce(t1.id, t2.id) as id, (coalesce(t1.value, 0) + coalesce(t2.value, 0)) as value
from table1 t1 full outer join table2 t2 on t1.id = t2.id
Use:
SELECT x.id,
SUM(x.value)
FROM (SELECT t.id,
t.value
FROM TABLE_1 t
UNION ALL
SELECT t2.id,
t2.value
FROM TABLE_2 t2) x
GROUP BY x.id
You could do it like this - but the other answers are probably swifter:
SELECT t1.id, t1.value + t2.value AS value
FROM t1 INNER JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.id, t1.value
FROM t1
WHERE t1.id NOT IN (SELECT t2.id FROM t2)
UNION
SELECT t2.id, t2.value
FROM t2
WHERE t2.id NOT IN (SELECT t1.id FROM t1)
SELECT
COALESCE(t1.id, t2.id) AS id,
COALESCE(t1.value, 0) + COALESCE(t2.value, 0) AS value
FROM
t1
FULL OUTER JOIN
t2 ON t1.id = t2.id
OR
SELECT
foo.id,
COALESCE(t1.value, 0) + COALESCE(t2.value, 0) AS value
FROM
(
SELECT t1.id FROM t1
UNION
SELECT t2.id FROM t2
) foo
LEFT JOIN
t1 ON foo.id = t1.id
LEFT JOIN
t2 ON foo.id = t2.id
SELECT ISNULL(T1.Col1.T2.Col1) as ID, (ISNULL(T1.Col2,0) + ISNULL(T2.Col2,0)) as SumCols
FROM T1 OUTER JOIN T2 ON T1.Col1 = T2.Col2
No grouping or anything. It handles the following cases
if an id is in T1 but not in T2 you will get the value in T1 and vice versa. This handles bi-directional inclusion.
If an ID is in both you will get the sum