mysql - get details from 2 tables with 1 query - sql

I have 2 mysql tables:
The first table table1:
| ID | NAME |
| 1 | cat |
| 2 | mouse |
| 3 | mouse |
| 4 | mouse |
| 5 | mouse |
| 6 | mouse |
The secound table table2:
| ID | NAME_NA |
| 1 | cat |
| 2 | mouse |
| 3 | cd_rom |
| 4 | dvd_rw |
| 5 | house |
And i want to output this :
mouse - 5 entries
cat - 1 entry
cd_rom - 0 entries
dvd_rw - 0 entries
house - 0 entries

Use a LEFT JOIN:
SELECT x.name_na AS name,
COALESCE(COUNT(y.name), 0) AS num_entries
FROM TABLE2 x
LEFT JOIN TABLE1 y ON y.name = x.name_na
...to get:
name num_entries
--------------------
mouse 5
cat 1
cd_rom 0
dvd_rw 0
house 0

SELECT `table1`.`NAME`, IFNULL(COUNT(*), 0) as entries FROM
`table2` LEFT JOIN `table1` ON `table1`.`NAME` = `table2`.`NAME_NA`
GROUP BY `table1`.`NAME`;
The LEFT JOIN creates rows for each item in the "left" table (table2 here) even if there's no match in table1, and also will create multiple rows for an item in table2 if there are multiple matching rows in table1 for that item.
Then if you GROUP BY the name and use a COUNT() function, you can get the count of how many matches each item in table2 has in table1.
The IFNULL() is utilized because COUNT() will return NULL if there weren't any matches for that item in table1, so we substitute in 0 instead.

Related

Update rows in one table depending on a column in another table

I have 2 tables in different databases in SQL Server.
database1.table_A
id | name | present |
-----|------------|-----------|
1 | jon | 1 |
2 | ham | 0 |
3 | sam | 1 |
7 | tom | 1 |
database2.table_B
absentid |
----------|
1 |
5 |
7 |
For every id value present in table_B, I want the value of present in table_A to be 0. So, my final result should look like -
id | name | present |
-----|------------|-----------|
1 | jon | 0 |
2 | ham | 0 |
3 | sam | 1 |
7 | tom | 0 |
I want to confirm if the following query I wrote is correct or if there are any better ways to do this:
update database1.table_A
set present=0
FROM database1.table_A t1
inner join
database2.table_B t2
ON t1.id = t2.absentid;
If you want to set present = 1 if they are not in the table, then you would use left join:
update t1
set present = (case when t2.absentid is null then 1 else 0 end)
from database1.table_A t1 left join
database2.table_B t2
on t1.id = t2.absentid;
Otherwise, if you want to keep the value in that case, your version is fine.

Select two tables side by side

I have two tables filled with two files of which table1 always has one row more than the second.
I want to merge the two tables into one. When I use a right join e.g.
select *
from table2
right join table1 on table1.id = table2.id and table1.eq_nb = table2.eq_nb
I will have the 4 combinations for eq_nb = 25 because it is repeated two times.
But I rather want to stick the columns side by side
To know, I don't have conditions on arrival and depart time of each eq_nb (I can't add something like datediff(second,table1.arrival_time,table2.depart_time) < X )
table1:
id | eq_nb | arival_time
-------------------------------------
1 | 25 | 05:30:15.231
-------------------------------------
2 | 50 | 06:30:15.231
-------------------------------------
3 | 7 | 07:30:15.231
-------------------------------------
1 | 25 | 08:30:15.231
-------------------------------------
5 | 27 | 09:30:15.231
-------------------------------------
table2:
id | eq_nb | depart_time
----------------------------------
1 | 25 | 05:31:15.231
----------------------------------
2 | 50 | 06:31:15.231
----------------------------------
3 | 7 | 07:31:15.231
----------------------------------
1 | 25 | 08:31:15.231
----------------------------------
desired result:
id | eq_nb | arrival_time | depart_time
-------------------------------------------------------
1 | 25 | 05:30:15.231 | 05:31:15.231
-------------------------------------------------------
2 | 50 | 06:30:15.231 | 06:31:15.231
-------------------------------------------------------
3 | 7 | 07:30:15.231 | 07:31:15.231
-------------------------------------------------------
1 | 25 | 08:30:15.231 | 08:31:15.231
--------------------------------------------------------
5 | 27 | 09:30:15.231 | NULL
--------------------------------------------------------
left join should do what you want:
select *
from table1 t1 left join
table2 t2
on t1.id = t2.id and t1.eq_nb = t2.eq_nb;
Given your data, the ids are unique, so there should be no duplication. Note: This is equivalent to your first query; left join is typically easier to follow because all the rows in the first table are in the result set.
Here is a db<>fiddle, illustrating that it works.

SQL : Comparing multiple values in one table with a single value in another Table

I have two tables Table 1 and Table 2
Table 1:
-------------------------------
| Ser | StartDate | Activity |
-------------------------------
| 1 | 2002-10-13 | 1 |
| 1 | 2002-10-13 | 2 |
| 1 | 2007-09-04 | 3 |
Table 2:
------------------------
|Ser|DateOfRegistration|
------------------------
| 1 | 2002-10-12 |
| 1 | 2007-09-02 |
Now, the result that I want is such that for Activity 1 and 2 the Date of registration should be before the Start Date and difference between the dates must be the least. Similarly, for Activity 3, the date of registration for Activity 3 should be before the start date. The result should look like this.
Table 3:
--------------------------------------------
|Ser|StartDate |DateofRegistration|Activity|
--------------------------------------------
| 1 |2002-10-13| 2002-10-12 | 1 |
| 1 |2002-10-13| 2002-10-12 | 2 |
| 1 |2002-09-04| 2002-09-02 | 3 |
How can I join Table 1 and 2 to get Table 3?
You can use outer apply:
select t1.*, t2.dateofregistration
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.ser = t1.ser and t2.dateofregistration < t1.startdate
order by t2.dateofregistration desc
) t2

Oracle ordering by several same meaning columns

I have to make sortable table like this:
Sortable table:
building_id | building_age | title |
-------------------------------------------------
1 | 100 | New york buil |
2 | 50 | House 1 |
3 | 50 | House 10 |
From these tables:
Building Table:
building_id | building_age | building_type_1_FK | building_type_2_FK
---------------------------------------------------------
1 | 100 | null | 1
2 | 50 | 1 | null
3 | 50 | 2 | null
building_type_1:
type_id | title | diff1 |
-------------------------------------------------
1 | New york buil| blablabla |
building_type_2:
building_id | title |
----------------------------
1 | House 1 |
2 | House 10 |
3 | House 500 |
While joining these tables I get several title columns where one of them is not null. Is there any way to sort by title and select top 10 results without fetching all the data and then sorting in the app?
p.s.. I know that in general this architecture is not good, but I can't change it.
Yes. You want to do a left outer join to the two tables, and then bring the results together:
select b.building_id, b.building_age, coalesce(bt1.title, bt2.title) as title
from building b left outer join
building_type_1 bt1
on b.building_type_1_FK = bt1.type_id left outer join
building_type_2 bt2
on b.building_type_2_FK = bt2.building_id;
To get the top 10 results in Oracle:
select *
from (select b.building_id, b.building_age, coalesce(bt1.title, bt2.title) as title
from building b left outer join
building_type_1 bt1
on b.building_type_1_FK = bt1.type_id left outer join
building_type_2 bt2
on b.building_type_2_FK = bt2.building_id
order by title
) b
where rownum <= 10;

Selecting column from one table and count from another

t1
id | name | include
-------------------
1 | foo | true
2 | bar | true
3 | bum | false
t2
id | some | table_1_id
-------------------------
1 | 42 | 1
2 | 43 | 1
3 | 42 | 2
4 | 44 | 1
5 | 44 | 3
Desired output:
name | count(some)
------------------
foo | 3
bar | 1
What I have currently from looking through other solutions here:
SELECT a.name,
COUNT(r.some)
FROM t1 a
JOIN t2 r on a.id=r.table_1_id
WHERE a.include = 'true'
GROUP BY a.id,
r.some;
but that seems to get me
name | count(r.some)
--------------------
foo | 1
foo | 1
bar | 1
foo | 1
I'm no sql expert (I can do simple queries) so I'm googling around as well but finding most of the solutions I find give me this result. I'm probably missing something really easy.
Just remove the second column from the group by clause
SELECT a.name,
COUNT(r.some)
FROM t1 a
JOIN t2 r on a.id=r.table_1_id
WHERE a.include = 'true'
GROUP BY a.name
Columns you want to use in an aggregate function like sum() or count() must be left out of the group by clause. Only put the columns in there you want to be unique outputted.
This is because multiple column group requires the all column values to be same.
See this link for more info., Using group by on multiple columns
Actually in you case., if some are equal, table_1_id is not equal (And Vice versa). so grouping cannot occur. So all are displayed individually.
If the entries are like,
id | some | table_1_id
-------------------------
1 | 42 | 1
2 | 43 | 1
3 | 42 | 2
4 | 42 | 1
Then the output would have been.,
name | count
------------------
foo | 2 (for 42)
foo | 1 (for 43)
bar | 1 (for 42)
Actually, if you want to group on 1 column as Juergen said, you could remove r.some; from groupby clause.