I'm kinda lost on what kind of SQL query I should do to achieve what I want.
Let's say I have three tables :
select * FROM trip;
| trip_id | title | description
----------------------------------
| 1 | title1 | desc1 |
| 2 | title2 | desc2 |
| 3 | title3 | desc3 |
| 4 | title4 | desc4 |
| 5 | title5 | desc5 |
| 6 | title6 | desc6 |
select * FROM weekly_report;
| report_id | trip_id| incident_id
----------------------------------
| 1 | 1 | (null) |
| 2 | 1 | (null) |
| 3 | 1 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 3 |
| 6 | 3 | (null) |
select * FROM incident;
| incident_id | error_code |
----------------------------------
| 1 | 22223 |
| 2 | 25456 |
| 3 | 25456 |
So for a little operationnal knowledge :
The trip table contains 1 record PER trip done by the customer.
The weekly_report contains A report per Week of the trip. (1 trip of 2 weeks will have 2 records, 1 trip or 5 weeks will have 5.. ).
The incident table contains 1 record per incident. (If an incident happened during a week : we create a record in the incident table, else we do nothing)
I'd like to find in a single query (or if it has to be, with subqueries) the number of trips where during at least a week there has been an incident declared for the error_code "25456".
Expected result from the sample data : 2 ( because for trip 2 and three there exist an incident with the error code 25456 ).
I can explain more if needed, is there anybody out there willing to help me ?
Thanks,
You need to take count of distinct trips for related incidents
select count(distinct w.trip_id)
from weekly_report w
inner join incident i
on w.incident_id = i.incident_id
where i.error_code = 25456;
Try this:
SELECT w.trip_id
FROM incident i
INNER JOIN weekly_report w ON i.incident_id=w.incident_id
WHERE error_code='25456'
and if you want the count,then
SELECT COUNT(w.trip_id)
FROM incident i
INNER JOIN weekly_report w ON i.incident_id=w.incident_id
WHERE error_code='25456'
Related
It's me again with my weird queries.
table users:
id | type | partner | company
------------------------------
1 | 2 | 0 | comp1
2 | 3 | 2 | comp2
3 | 3 | 2 | comp3
4 | 3 | 3 | comp4
table orders:
id | user | partner
--------------------
1 | 2 | 2
2 | 2 | 2
3 | 2 | 3
4 | 3 | 2
I know it's a little hart to keep track of all these numbers.
I'm logged in as type 2(users table) and want to get listed all information from the orders table from the users with type 3 and which are listed as my partners (partner 2) in addition I want the company name from the users table also in my results.
The query will be excecuted on the orders table.
result:
id | user | partner | company
------------------------------
1 | 2 | 2 | comp2
2 | 2 | 2 | comp2
4 | 3 | 2 | comp3
Thanks in advance and ask me if you don't understand the problem. I will try to explain better and any edits to make it more clear are also welcomed.
Perhaps this
select s.id,
case when src = 'u' then s.users
else s.partner
end as users,
case when src = 'p' then s.users
else s.partner
end as partner,
u.company
from
(
select 'u' as src,id,users,partner from o where users = 2 and (users = partner)
union
select 'p',id,partner,users from o where partner = 2 and (users <> partner)
) s
join u on u.id = s.partner
where type = 3;
Hopefully self explanatory, note I only need to know the user, the query figures out the partners.
result
+------+-------+---------+---------+
| id | users | partner | company |
+------+-------+---------+---------+
| 2 | 2 | 2 | comp2 |
| 1 | 2 | 2 | comp2 |
| 4 | 3 | 2 | comp3 |
+------+-------+---------+---------+
3 rows in set (0.00 sec)
I have 3 tables: NAMES, REGISTRATIONS, and RENEWALS. I'm using LEFT JOIN to join the 3 tables with a common ID.
I need to count the number of REGISTRATIONS of each user, as well as the number of RENEWALS. I've tried using different options in the GROUP BY field, but none seemed to work.
Here's the SELECT statement:
SELECT
names.name_id AS 'Names ID'
,names.name AS Name
,count(registrations.date) AS Registrations
,count(renewals.date) AS Renewals
FROM names
LEFT JOIN registrations
ON names.name_id = registrations.name_id
LEFT JOIN renewals
ON renewals.name_id = registrations.name_id
GROUP BY names.name_id, registrations.name_id, renewals.name_id;
And here are the 3 tables:
TABLE: names
+---------+------+
| name_id | name |
+---------+------+
| 1 | Ana |
| 2 | John |
| 3 | Paul |
+---------+------+
TABLE: registrations
+-----------------+---------+---------------------+-------+
| registration_id | name_id | date | value |
+-----------------+---------+---------------------+-------+
| 1 | 1 | 2014-01-30 13:15:02 | 15 |
| 2 | 2 | 2014-05-01 18:01:44 | 15 |
| 3 | 2 | 2014-07-08 15:10:43 | 20 |
| 4 | 3 | 2012-09-28 17:45:32 | 15 |
| 5 | 3 | 2014-01-09 18:26:14 | 20 |
| 6 | 3 | 2015-01-10 13:22:01 | 25 |
+-----------------+---------+---------------------+-------+
TABLE: renewals
+------------+---------+---------------------+-------+
| renewal_id | name_id | date | value |
+------------+---------+---------------------+-------+
| 1 | 1 | 2015-01-30 00:00:00 | 5 |
| 2 | 1 | 2016-02-12 00:00:00 | 5 |
| 3 | 1 | 2015-06-01 00:00:00 | 5 |
| 4 | 1 | 2013-11-24 00:00:00 | 5 |
| 5 | 2 | 2015-01-27 00:00:00 | 5 |
+------------+---------+---------------------+-------+
Here's the INCORRECT result I'm getting:
+----------+------+---------------+----------+
| Names ID | Name | Registrations | Renewals |
+----------+------+---------------+----------+
| 1 | Ana | 4 | 4 |
| 2 | John | 2 | 2 |
| 3 | Paul | 3 | 0 |
+----------+------+---------------+----------+
The CORRECT result I was expecting would be:
+----------+------+---------------+----------+
| Names ID | Name | Registrations | Renewals |
+----------+------+---------------+----------+
| 1 | Ana | 1 | 4 |
| 2 | John | 2 | 1 |
| 3 | Paul | 3 | 0 |
+----------+------+---------------+----------+
How can I fix the query to get a correct result?
Try this:
SELECT
names.name_id AS 'Names ID'
,names.name AS Name
,count(distinct registrations.registration_id) AS Registrations
,count(distinct renewals.renewal_id) AS Renewals
FROM names
LEFT JOIN registrations
ON names.name_id = registrations.name_id
LEFT JOIN renewals
ON renewals.name_id = registrations.name_id
GROUP BY names.name_id, registrations.name_id, renewals.name_id;
Whenever I run into this type of issue, I find it helps to just run a select * query if your server can take it. Like this:
SELECT *
FROM names
LEFT JOIN registrations
ON names.name_id = registrations.name_id
LEFT JOIN renewals
ON renewals.name_id = registrations.name_id ;
That will let you see what you are really counting.
Your query is executed just fine.
After the first join you have 1 entry for Ana, 2 entries for John and 3 for Paul.
After the seconds join the one entry for Ana is duplicated 4 times and joined (concatenated) with the 4 renewals. If you now count the registration dates for Ana you get 4. That is where your "errors" come from.
You could for example count the distinct dates to fix it.
I am trying to group a record only if two of the fields repeat themselves.
I am designing a social sharing photo app. users can share, like and comment on thers photo. Each action (share, comment, like) will appear on their friends wall.
The Problem is that when a user do all the three actions, the picture appears three times instead of one with the three action on it.
Data in database is like this (activities_tb)
id | photoID | uiID | action | date
-------------------------------------------
1 | 1 | 2 | like | 01/01/2015
2 | 1 | 2 | share | 02/01/2015
3 | 1 | 4 | share | 03/01/2015
4 | 1 | 2 | comment | 04/01/2015
5 | 2 | 4 | like | 04/01/2015
6 | 2 | 2 | like | 05/01/2015
7 | 2 | 3 | share | 05/01/2015
8 | 2 | 4 | comment | 06/01/2015
8 | 3 | 3 | like | 07/01/2015
9 | 3 | 5 | like | 08/01/2015
10 | 3 | 5 | comment | 08/01/2015
The query result I want to get
id | photoID | uiID | action | date
-------------------------------------------
3 | 1 | 4 | share | 03/01/2015
4 | 1 | 2 | comment | 04/01/2015
6 | 2 | 2 | like | 05/01/2015
7 | 2 | 3 | share | 05/01/2015
8 | 2 | 4 | comment | 06/01/2015
8 | 3 | 3 | like | 07/01/2015
10 | 3 | 5 | comment | 08/01/2015
This is my statement
SELECT id, photoID, uiID, action, date
FROM activities_tb
GROUP BY photoID, uiID.
This combines all the photos by their id returning only three results
I will be glad if anyone can be of help, thank you
You can first select required ids and join on your table:
select tb.*
from activities_tb tb
join(select max(id) as id
from activities_tb
group by photoID, uiID) t on t.id = tb.id
You are looking for "SELECT DISTINCT"
SELECT DISTINCT photoID, uiID, action, date
FROM activities_tb
GROUP BY photoID, uiID.
I want to calculate a value for NO_TOP_RATING in my table working
The calculation for NO_TOP_RATING is made by:
For each row, get all other rows that fall within the previous year from ANNDATS_CONVERTED for that record, and have the same ESTIMID as that record.
From those, find the lowest IRECCD value.
Then, count the number of times that the same ANALYST has an IRECCD that matches the lowest IRECCD calculated.
NOTE: This should omit the current row being calculated (so to find the value for row id 1, do not use this row in the calculations) and any records where ANALYST is blank should be ignored altogether.
TABLE working:
| ID | ANALYST | ESTIMID | ANNDATS_CONVERTED | IRECCD | NO_TOP_RATING |
---------------------------------------------------------------------------------
| 1 | DAVE | Brokerage000 | 1998-07-01 | 2 | |
| 2 | DAVE | Brokerage000 | 1998-06-28 | 2 | |
| 3 | DAVE | Brokerage000 | 1998-07-02 | 4 | |
| 4 | DAVE | Brokerage000 | 1998-07-04 | 3 | |
| 5 | SAM | Brokerage000 | 1998-06-14 | 1 | |
| 6 | SAM | Brokerage000 | 1998-06-28 | 4 | |
| 7 | | Brokerage000 | 1998-06-28 | 1 | |
| 8 | DAVE | Brokerage111 | 1998-06-28 | 5 | |
So - when calculating NO_TOP_RATING for record #1:
record #1 would not be included in the calculation, because I want to omit it from the calculation
record #7 would not be included in the calculation at all, because ANALYST is blank
Record #8 would not be included in the calculation, because ESTIMID is not the same as record #1
EXPECTED RESULT:
TABLE working:
| ID | ANALYST | ESTIMID | ANNDATS_CONVERTED | IRECCD | NO_TOP_RATING |
---------------------------------------------------------------------------------
| 1 | DAVE | Brokerage000 | 1998-07-01 | 2 | 0 |
| 2 | DAVE | Brokerage000 | 1998-06-28 | 2 | 0 |
| 3 | DAVE | Brokerage000 | 1998-07-02 | 4 | 0 |
| 4 | DAVE | Brokerage000 | 1998-07-04 | 3 | 0 |
| 5 | SAM | Brokerage000 | 1998-06-14 | 1 | 0 |
| 6 | SAM | Brokerage000 | 1998-06-28 | 4 | 1 |
| 7 | | Brokerage000 | 1998-06-28 | 1 | |
| 8 | DAVE | Brokerage111 | 1998-06-28 | 5 | 0 |
Here is the MySQL I have so far:
UPDATE `working`
SET `working`.`NO_TOP_RATING` =
(
SELECT COUNT(`ID`) FROM (SELECT `ID`,`IRECCD`,`ESTIMID` FROM `working`) AS BB
WHERE
`IRECCD` =
(
SELECT COUNT(`ID`) FROM (SELECT `ID`,`IRECCD`,`ESTIMID`, `ANALYST` FROM `working`) AS ZZ
WHERE
`IRECCD` =
-- this calculates the LOWEST number with same `ESTIMID`
(
SELECT MIN(`IRECCD`)
FROM (SELECT `ID`,`IRECCD`,`ANNDATS_CONVERTED`,`ESTIMID` FROM `working`) AS CC
WHERE
`ANNDATS_CONVERTED` >= DATE_SUB(`ANNDATS_CONVERTED`,INTERVAL 1 YEAR)
AND
`working`.`ESTIMID` = BB.`ESTIMID`
)
-- END this calculates the LOWEST number with same `ESTIMID`
AND
`working`.`ANALYST` = ZZ.`ANALYST`
)
)
WHERE `working`.`ANALYST` != ''
This is working in PHP, looping through each record and evaluating all the other records for each. This involves looping and takes a very long time on a large database. I am trying to achieve the same result with MySQL.
I took a few steps to solve this. The first thing I did was write a JOIN that got all of the rows I needed. I joined the table to itself on several conditions:
The estimid matched
The id value was not the same
The analyst column was not null in either table
The anndats_converted of one table was within the previous year of the other table.
To test, I selected the id from both tables to make sure I was getting proper pairings:
SELECT w.id, wo.id
FROM working w
JOIN working wo
ON w.estimid = wo.estimid
AND w.id != wo.id
AND w.analyst IS NOT NULL
AND wo.analyst IS NOT NULL
AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
ORDER BY w.id;
A brief result set showed the following pairings:
| id | id |
+----+----+
| 1 | 2 |
| 1 | 5 |
| 1 | 6 |
| 2 | 5 |
| 2 | 6 |
This seems to match what you wanted. For id #1, row 1 is excluded (because it is being calculated) rows 3 and 4 do not fall in the proper date range, row 7 is null and row 8 is a different estimid.
Then, I used an aggregate function to calculate the minimum ireccd by grouping by the first table:
SELECT w.id, w.analyst, MIN(wo.ireccd) AS min_ireccd
FROM working w
JOIN working wo
ON w.estimid = wo.estimid
AND w.id != wo.id
AND w.analyst IS NOT NULL
AND wo.analyst IS NOT NULL
AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
GROUP BY w.id;
The next part was also tricky so I'll explain it in two steps. I joined the above query with the original table, with the only condition that the analyst column matched. What this did was create a Cartesian Product, in a way. The query looked like this:
SELECT *
FROM working w
LEFT JOIN(
SELECT w.id, w.analyst, MIN(wo.ireccd) AS min_ireccd
FROM working w
LEFT JOIN working wo
ON w.estimid = wo.estimid
AND w.id != wo.id
AND w.analyst IS NOT NULL
AND wo.analyst IS NOT NULL
AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
GROUP BY w.id) temp ON temp.analyst = w.analyst;
And I saw all possible pairings for each person, like this:
| id | analyst | ireccd | id | analyst | min_ireccd |
+----+---------+--------+----+---------+------------+
| 1 | DAVE | 2 | 8 | DAVE | null |
| 1 | DAVE | 2 | 4 | DAVE | 1 |
| 1 | DAVE | 2 | 1 | DAVE | 1 |
| 1 | DAVE | 2 | 2 | DAVE | 1 |
| 1 | DAVE | 2 | 3 | DAVE | 1 |
Notice that compares the first DAVE with all other rows of DAVE in the table. ALSO NOTE I changed the above inner query to include an outer join so that all rows were considered. If there was nothing to calculate, the min_ireccd would be null.
The last thing I did was use that result set, and count the number of times the ireccd matched the min_ireccd. I grouped by id, so in the above sample set, it never matches, so the count would be 0. Here is the final query. It leaves null values (row 7) as null because that's what your expected results show:
SELECT w.*, SUM(w.ireccd = temp.min_ireccd) AS NO_TOP_RATING
FROM working w
LEFT JOIN(
SELECT w.id, w.analyst, MIN(wo.ireccd) AS min_ireccd
FROM working w
LEFT JOIN working wo
ON w.estimid = wo.estimid
AND w.id != wo.id
AND w.analyst IS NOT NULL
AND wo.analyst IS NOT NULL
AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
GROUP BY w.id) temp ON temp.analyst = w.analyst
GROUP BY w.id;
These are the results I got:
I've got two tables in my database. Table 1 is a list of "timelines" and their corresponding owners and title.
Table 2 is a list of users who have access to the timelines but are followers, not owners.
I'm trying to write a query that outputs the lineID's and corresponding titles that are linked to a userID in either of the two tables.
A query for userID 1 would ideally output:
1 a
2 b
3 c
6 f
Hopefully this isn't too confusing but the purpose is to fill a dynamically generated select box with the LineID and Title for a given UserID...
Table 1 ("owners")
--------------------------
| LineID | UserID | Title |
| 1 | 1 | a |
| 2 | 1 | b |
| 3 | 1 | c |
| 4 | 2 | d |
| 5 | 2 | e |
| 6 | 1 | f |
--------------------------
Table 2 ("followers")
----------------------------
| RowID | LineID | UserID |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 3 | 1 |
| 4 | 3 | 2 |
| 5 | 2 | 2 |
| 6 | 6 | 1 |
----------------------------
I tried using:
SELECT title
FROM `lines`
LEFT JOIN follow
ON follow.user_id = lines.user_id
WHERE follow.user_id = 1
That ended up producing duplicate rows.
The output I need would ideally be an array consisting of all the lineID's and Titles associated with that userID.
select LineId, Title
from owners
where LineId in (select LineId from followers group by LineId )
order by owners.LineId