Trouble joining tables - mysql

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

Related

Issue concatenating rows with duplicates

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];

SQL Query to join 3 tables, resulting a ordered and sorted list

How can I write a Query to join 3 tables, resulting a ordered and sorted list?

I have 3 tables with the following structure
:
Table Users:
|---------------------------|
| Users |
|---------------------------|
| ID | Name |
|-------------|-------------|
| 1 | John |
|-------------|-------------|
| 2 | David |
|-------------|-------------|
| 3 | James |
|-------------|-------------|
| 4 | Jack |
|-------------|-------------|
Table Questions:
|-------------------------------------------------------|
| Questions |
|-------------------------------------------------------|
| ID | Question |
|-------|-----------------------------------------------|
| 1 | How old are you working in this company? |
|-------|-----------------------------------------------|
| 2 | How many customers do you notice? |
|-------|-----------------------------------------------|
| 3 | What is your salary? |
|-------|-----------------------------------------------|
| 4 | Do you speak another language? |
|-------|-----------------------------------------------|
Table Replies
|----------------------------------------|
| Replies |
|----------------------------------------|
| ID | USER ID | QUESTION ID | Reply |
|-----|---------|-------------|----------|
| 1 | 1 | 1 | 10 |
|-----|---------|-------------|----------|
| 2 | 1 | 2 | 30 |
|-----|---------|-------------|----------|
| 3 | 1 | 3 | 3000 |
|-----|---------|-------------|----------|
| 4 | 1 | 4 | yes |
|-----|---------|-------------|----------|
| 5 | 2 | 1 | 7 |
|-----|---------|-------------|----------|
| 6 | 2 | 2 | 25 |
|-----|---------|-------------|----------|
| 7 | 2 | 3 | 1500 |
|-----|---------|-------------|----------|
| 8 | 2 | 4 | no |
|-----|---------|-------------|----------|
| 9 | 3 | 1 | 5 |
|-----|---------|-------------|----------|
| 10 | 3 | 2 | 50 |
|-----|---------|-------------|----------|
| 11 | 3 | 3 | 2000 |
|-----|---------|-------------|----------|
| 12 | 3 | 4 | yes |
|-----|---------|-------------|----------|
| 13 | 4 | 1 | 7 |
|-----|---------|-------------|----------|
| 14 | 4 | 2 | 40 |
|-----|---------|-------------|----------|
| 15 | 4 | 3 | 2000 |
|-----|---------|-------------|----------|
| 16 | 4 | 4 | yes |
|-----|---------|-------------|----------|
I need to write a SQL Query to filter and sort these results.
Almost like an Excel.


Example:
I need to select who speaks another language, who serves from 5 to 100 clients, ordering for the decreasing salary and years in the descending company.

It should result like this:
|--------------------------------------------------------------------|
| Result |
|--------------------------------------------------------------------|
| ORDER | NAME | QUESTION 1 | QUESTION 2 | QUESTION 3 | QUESTION 4 |
|-------|--------|------------|------------|------------|------------|
| 1 | John | 10 | 30 | 3000 | Yes |
|-------|--------|------------|------------|------------|------------|
| 2 | Jack | 7 | 40 | 2000 | Yes |
|-------|--------|------------|------------|------------|------------|
| 3 | James | 5 | 50 | 2000 | Yes |
|-------|--------|------------|------------|------------|------------|
Any suggestions?
Thanks
Do the JOIN with conditional aggregation :
select u.user_id, u.name,
max(case when r.QUESTIONID = 1 then r.reply) as QUESTION1,
max(case when r.QUESTIONID = 2 then r.reply) as QUESTION2,
max(case when r.QUESTIONID = 3 then r.reply) as QUESTION3,
max(case when r.QUESTIONID = 4 then r.reply) as QUESTION4
from Replies r inner join
Users u
on u.user_id = r.user_id
group by u.user_id, u.name;
EDIT :
select t.*
from ( <query> ) t
where . . .;

Select once for duplicate record

This is my tables which I need get data from these tables. Each user can under many type of groups for example 2, 3, 4
1)groups
|gp_id|gp_name|gp_status|
-------------------------------------
| 1 | Admin | Active |
| 2 | R&D | Active |
| 3 | Sales | Active |
| 4 | IT | Active |
2)modules (FK of table parent_modules)
|mod_id| mod_name| pmod_id |
---------------------------------------------
| 1 | name1 | 1 |
| 2 | name2 | 1 |
| 3 | name3 | 2 |
| 4 | name4 | 3 |
| ... | name... | 3 |
mod_id = 5,6,7.. and so on
3)parent_modules
|pmod_id| mod_name |pmod_status|
-----------------------------------------
| 1 | Contact Us | Active |
| 2 | Account Settings | Active |
| 3 | System Settings | Active |
4)group_details
(FK of table groups) (FK of table modules)
|gpd_id | gp_id | mod_id | base_gpd_rule_view/edit/update/insert |
-----------------------------------------------------------------------
| 1 | 3 | 1 | on |
| 2 | 3 | 2 | on |
| 3 | 3 | 3 | |
| 4 | 3 | 4 |
| 5 | 3 | 5 | on |
| 6 | 3 | 6 |
| 7 | 3 | 7 |
| 8 | 4 | 6 |
| 9 | 4 | 7 | on |
| 10 | 4 | 8 | on |
I have to select once only of duplicate results from group_details and this is the result that I want.
| gp_id | mod_id |
----------------------------------------------
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
| 3 | 5 |
| 3 | 6 |
| 3 | 7 |
| 4 | 8 |
So far this is what I did in my query but it shows me duplicate record.
//get user groups store in database. example group in database:2, 3, 4
$GroupList = explode(", ", $UserDetail['u_group']);
foreach($GroupList as $a)
{
$getParentModuleSQL = base_executeSQL("SELECT * FROM parent_modules WHERE pmod_status<>'Disable'" );
$count1 = base_num_rows($getParentModuleSQL);
while($ParentModuledata_row = base_fetch_array($getParentModuleSQL))
if ($count1!= 0)
{
base_executeSQL("SELECT gp.gp_id AS ID FROM group_details AS gp, modules AS m WHERE m.pmod_id =". $ParentModuledata_row['pmod_id'] ." AND gp.gp_id=". $a ." AND gp.mod_id = m.mod_id" AND (base_gpd_rule_view='on' OR base_gpd_rule_add='on' OR base_gpd_rule_edit='on' OR base_gpd_rule_delete='on') GROUP BY gp.mod_id);
}
}
i still dont understand your problems. if you want all modules a gp_id has access to - select * from group_details where gp_id = XX. If you just want each module, select * from modules.

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.

SQL node path reconstruction

I have a table which contains data about which node has been visited. It is possible that a node can be visited several times. For this I have another table which contains data of the visited node, node visited before and the node visited after. I would now like to reconstruct the path in order of visitation using MySQL. I can't seem to figure out how to make a query for this, so I'm asking here for help.
Example
Let's say someone visited these nodes in this order:
4->5->6->7->4->6->10->12->7->15
The tables would look like this:
Visits
+---------+-------------------------------+----------+------------+
| id | user | node | view_count |
+---------+-------------------------------+----------+------------+
| 1 | l3lie1frl77j135b3fehbjrli5 | 4 | 2 |
+---------+-------------------------------+----------+------------+
| 2 | l3lie1frl77j135b3fehbjrli5 | 5 | 1 |
+---------+-------------------------------+----------+------------+
| 3 | l3lie1frl77j135b3fehbjrli5 | 6 | 2 |
+---------+-------------------------------+----------+------------+
| 4 | l3lie1frl77j135b3fehbjrli5 | 7 | 2 |
+---------+-------------------------------+----------+------------+
| 5 | l3lie1frl77j135b3fehbjrli5 | 10 | 1 |
+---------+-------------------------------+----------+------------+
| 6 | l3lie1frl77j135b3fehbjrli5 | 12 | 1 |
+---------+-------------------------------+----------+------------+
| 7 | l3lie1frl77j135b3fehbjrli5 | 15 | 1 |
+---------+-------------------------------+----------+------------+
Revisits
+---------+-------------------------------+-------+----------------+-----------------+
| id | user | node | after_visiting | before_visiting |
+---------+-------------------------------+-------+----------------+-----------------+
| 1 | l3lie1frl77j135b3fehbjrli5 | 4 | 7 | 6 |
+---------+-------------------------------+-------+----------------+-----------------+
| 2 | l3lie1frl77j135b3fehbjrli5 | 6 | 4 | 10 |
+---------+-------------------------------+-------+----------------+-----------------+
| 3 | l3lie1frl77j135b3fehbjrli5 | 7 | 12 | 15 |
+---------+-------------------------------+-------+----------------+-----------------+
I would like to construct a query that would return the path in the form of a string or a list of nodes like this:
4,5,6,7,4,6,10,12,7,15
or
+---------+--------+
| index | node |
+---------+--------+
| 1 | 4 |
+---------+--------+
| 2 | 5 |
+---------+--------+
| 3 | 6 |
+---------+--------+
| 4 | 7 |
+---------+--------+
| 5 | 4 |
+---------+--------+
| 6 | 6 |
+---------+--------+
| 7 | 10 |
+---------+--------+
| 8 | 12 |
+---------+--------+
| 9 | 7 |
+---------+--------+
| 10 | 15 |
+---------+--------+
Any help will be much appreciated.
change your design to have 1 table visits:
+----+------+------+
| id | user | node |
+----+------+------+
| 1 | xx | 4 |
| 2 | xx | 5 |
| 3 | xx | 6 |
| 4 | xx | 7 |
| 5 | xx | 4 |
| 6 | xx | 6 |
| 7 | xx | 10 |
| 8 | xx | 12 |
| 9 | xx | 7 |
| 10 | xx | 15 |
+----+------+------+
you can then select view_count like this:
select node, count(*) view_count
from visits
where user = :user
group by node
and path like this:
select group_concat(node order by id separator ',') path
from visits
where name = :name