Issue concatenating rows with duplicates - mysql

I have run into some issues trying to combine a row of variables where dublicates can be found.
Computers with Ids are saved in the Computer table:
| Computer.Id |
|-------------|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
Harddrive are saved in a HardDisk table with a HardDisk Id exclusive to the harddrive and a ComputerId linked to the Id in the Computer table
| Harddisk.ComputerId | Harddisk.Id |
|---------------------|-------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 6 | 7 |
| 7 | 8 |
| 8 | 9 |
| 9 | 10 |
The output I am looking to achieve is:
| Harddisk.ComputerId | Harddisk.Id |
|---------------------|-------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6,7 |
| 7 | 8 |
| 8 | 9 |
| 9 | 10 |
The output I'm currently getting is:
| Harddisk.ComputerId | Harddisk.Id |
|---------------------|-------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 8 |
| 8 | 9 |
| 9 | 10 |
Notice how Harddisk 7 which is the disk that shares Computer 6 is gone.
My current query looks like the following, courtesy of scaisEdge:
SELECT *, group_concat(HardDisk.Id)
from Computer
inner join HardDisk on Computer.Id = HardDisk.ComputerId
group by Computer.Id
I hope someone is able to help me out!

You can't use * because this produce an a wrong aggregation in mysql for version < 5.7
try use explicit column's name in select
SELECT computer.ID, group_concat(HardDisk.Id) my_disk
from Computer
inner join HardDisk on Computer.Id = HardDisk.ComputerId
group by Computer.Id
if you need more column's not related to the same aggreagtion level you need a join
In mysql version < 5.7 if some columns mentioned in select clause are not mentioned properly in group by the aggregation function return the first occurrence of the select and not the correct aggreagted result
try add
echo $row['my_disk];

Related

Trouble joining tables

I am trying to make an SQL query that joins three tables and lists a value from two of them.
My current setup is the following:
| Computer(Id) |
|----|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
The harddrives have a unique ID an an associated computer linked by ComputerId
| HardDisk(Id) | HardDisk(ComputerId) |
|---- |-------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 6 |
| 8 | 7 |
| 9 | 8 |
| 10 | 9 |
Disks have log associated with them. These logs have a unique Id and a HardDiskId which is the disk that the log is associated with
| DiskLog(Id) | DiskLog(HardDiskId) |
|---- |------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 7 |
| 7 | 6 |
| 8 | 8 |
| 9 | 9 |
| 10 | 10 |
The output I'm looking for is this:
| Computer(Id) | HardDisk(Id) / DiskLog(Id) |
|------------|------------|
| 1 | 1 /1 |
| 2 | 2 / 2 |
| 3 | 3 / 3 |
| 4 | 4 / 4 |
| 5 | 5 / 5 |
| 6 | 7,6 / 6,7 |
| 7 | 8 / 8 |
| 8 | 9 / 9 |
| 9 | 10 / 10 |
I'm trying to get the ComputerId and the associated HardDisk which is found through the DiskLog to be outputted together
I currently have the following query, but it is not working as intended:
SELECT *, group_concat(Computer.Id) Target
from Computer
inner join HardDisk on Computer.Id = HardDisk.ComputerId
inner join DiskLog on HardDisk.Id = DiskLog.Id
group by Computer.Id
Consider the following query:
SELECT
c.Id AS ComputerId,
CONCAT(GROUP_CONCAT(DISTINCT h.Id),
' / ',
GROUP_CONCAT(d.Id)) AS hd_disk_ids
FROM Computer c
LEFT JOIN HardDisk h ON c.Id = h.ComputerId
LEFT JOIN DiskLog d ON d.HardDiskId = h.Id
GROUP BY c.Id;
Demo

How to find all the employees that under a manger who is also an employee in mySQL version 5.7.22 without using CTE and no pre defined manager level?

ManagerId is nothing but EmpId. i need all the EmpId that come under the given EmpId including all the subtree. without using CTE as i'm trying this with HQL. with no hierarchy level defined.
+-------+-----------+
| EmpId | ManagerId |
+-------+-----------+
| 1 | null |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 1 |
| 6 | 3 |
| 7 | 6 |
| 8 | 6 |
| 9 | null |
| 10 | 3 |
| 11 | 10 |
| 12 | 1 |
| 13 | 12 |
+-------+-----------+
when the givem EmpId is 3:
expected response:
4
6
10
7
8
11

MySQL find entries matching multiple pivot rows

I have a schema with 3 regular tables and 2 link tables like so:
tutorial
id
exam
id
user
id
exam_user
user
exam
tutorial_user
user
tutorial
Where the link tables determine which users have attended which exam/tutorial.
Starting with an exam ID, I'm trying to find tutorials whose members have ALL attended the exam.
For example:
exam_user
+----+-------+----------+
| id | exam | user |
+----+-------+----------+
| 23 | 8 | 1 |
| 24 | 8 | 5 |
| 25 | 8 | 8 |
| 26 | 8 | 11 |
| 27 | 8 | 12 |
+----+-------+----------+
tutorial_user
+----+----------+----------+
| id | tutorial | user |
+----+----------+-----------
| 56 | 2 | 1 |
| 57 | 2 | 5 |
| 58 | 2 | 8 |
| 59 | 2 | 11 |
+----+----------+----------+
+----+----------+----------+
| id | tutorial | user |
+----+----------+-----------
| 60 | 3 | 1 |
| 61 | 3 | 5 |
| 62 | 3 | 8 |
| 63 | 3 | 15 |
+----+----------+----------+
Tutorial 2 would match because all entries are in exam 8, but tutorial 3 would not because user 11 is not present.
Is there any (relatively) efficient way to achieve the above?
How about you try something like this:
select * from tutorial_user where tutorial not in
(
select tutorial from
(
(
select ex.exam, ex.user as ex_user, tut.tutorial as tutorial,
tut.user as tut_user from exam_user ex
inner join tutorial_user tut on
ex.User = tut.User
)
union all
(
select null, null, tutorial, user as tut_user from tutorial_user
)
) src
group by tutorial, tut_user
having count(tut_user) = 1
)
Now the first query should give you a list that looks like this (essentially a combination of exams and tutorials for every user):
+----+-------+----------+-------------+---------+
| id | exam | user | Tutorial | User |
+----+-------+----------+-------------+---------+
| 23 | 8 | 1 | 2 | 1 |
| 23 | 8 | 1 | 3 | 1 |
| 24 | 8 | 5 | 2 | 5 |
| 24 | 8 | 5 | 3 | 5 |
...
Next, by doing a union all with the next query, you'll end up with something like this:
+-----+-------+----------+-------------+---------+
| id | exam | user | Tutorial | User |
+-----+-------+----------+-------------+---------+
| 23 | 8 | 1 | 2 | 1 |
| 23 | 8 | 1 | 3 | 1 |
| 24 | 8 | 5 | 2 | 5 |
| 24 | 8 | 5 | 3 | 5 |
| null| null | null | 2 | 1 |
| null| null | null | 2 | 5 |
| null| null | null | 2 | 8 |
...
Basically, what this allows us to do is a group by statement that's going to highlight users in the tutorial table and not in the exam table. The said highlight is going to be with the having() clause. If the count is 1, then you have someone in the tutorial table that's not in the exam table. All you have to do now is select the tutorials from the tutorial table that are NOT part of what you found and you should be good.

Unique ID when creating Hive table from CSV files

I have a list of CSV files that I want to export as Hive tables but I'm pretty sure that some records are redundant in the CSVs. Each record / row in the CSV are identified by a key and I want to generate the table using that key as the primary key . How will I generate the Hive table such that there are no repeating rows?
ROW_NUMBER() OVER([partition_by_clause] order_by_clause)
returns an ascending sequence of integers, starting with 1.
select x, row_number() over(order by x, property) as row_number, property from int_t;
+----+------------+----------+
| x | row_number | property |
+----+------------+----------+
| 1 | 1 | odd |
| 1 | 2 | square |
| 2 | 3 | even |
| 2 | 4 | prime |
| 3 | 5 | odd |
| 3 | 6 | prime |
| 4 | 7 | even |
| 4 | 8 | square |
| 5 | 9 | odd |
| 5 | 10 | prime |
| 6 | 11 | even |
| 6 | 12 | perfect |
| 7 | 13 | lucky |
| 7 | 14 | lucky |
| 7 | 15 | lucky |
| 7 | 16 | odd |
| 7 | 17 | prime |
| 8 | 18 | even |
| 9 | 19 | odd |
| 9 | 20 | square |
| 10 | 21 | even |
| 10 | 22 | round |
+----+------------+----------+

MySQL how to find averages / day for different clients with different creation days

I've tried the following queries but unfortunately they don't work :(.
Worth mentioning that each customer has more than one CustomerUsers
select (a.TotalJobs / b.DaysActive) from
(select count(jr.id) as TotalJobs
from jobrequests jr, customers c, customerusers cu
where jr.customeruserid=cu.id
and cu.customerid=c.id
group by c.name) as a,
(select datediff(curdate(), from_unixtime(c.CreationTime)) as DaysActive
from customers c
group by c.name) as b
Please see below the tables
Jobs:
+----+--------------+
| ID | JobRequestID |
+----+--------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
| 8 | 3 |
| 9 | 3 |
| 10 | 3 |
| 11 | 4 |
| 12 | 4 |
| 13 | 5 |
| 14 | 5 |
| 15 | 6 |
| 16 | 7 |
| 17 | 8 |
| 18 | 8 |
| 19 | 9 |
| 20 | 10 |
+----+--------------+
JobRequests:
+----+---------------+
| ID | CustomeUserID |
+----+---------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 4 |
| 8 | 4 |
| 9 | 4 |
| 10 | 5 |
| 11 | 5 |
| 12 | 5 |
| 13 | 6 |
| 14 | 6 |
| 15 | 7 |
+----+---------------+
CustomerUsers:
+----+------------+
| ID | CustomerID |
+----+------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 3 |
| 9 | 3 |
| 10 | 4 |
+----+------------+
Customers:
+----+------+--------------+
| ID | Name | CreationTime |
+----+------+--------------+
| 1 | a | 1415814194 |
| 2 | b | 1415814194 |
| 3 | c | 1415986994 |
| 4 | d | 1415986994 |
+----+------+--------------+
For the moment it returns 16 results (4X4), dividing each result from 1st sub-query to each result from the 2nd one (each of these sub-queries return 4 results). Can anyone please help me to get this to divide only 1 result from sub-query 1 to it's corespondent from sub-query 2?
Thank you in advance.
I suspect that you can do what you want this a query like this:
select c.name, count(*) / (datediff(curdate(), from_unixtime(c.CreationTime))
from customerusers cu join
jobrequests jr
on jr.customeruserid = cu.id join
customers c
on cu.customerid = c.id
group by c.name;
I don't see why you need two subqueries for this.
I'm guessing you need to join your results together -- as currently written, you're producing a cartesian product.
Try something like this adding c.id to each subquery (it's better to group by it presumably rather than the name):
select (a.TotalJobs / b.DaysActive)
from (
select c.id,
count(jr.id) as TotalJobs
from jobrequests jr
join customers c on jr.customeruserid=cu.id
join customerusers cu on cu.customerid=c.id
group by c.id) a join (
select c.id,
datediff(curdate(), from_unixtime(c.CreationTime)) as DaysActive
from customers c
group by c.id) b on a.id = b.id
Please note, I've updated your syntax to use the more standard join syntax.