SQL calculating time between assignments - mysql

I have to write an SQL statement which contain a field that contain two different values consecutively but in the way I have wrote it, it return always null because it is interpreted as having the two value in the same time!
My conditions should be : (ci.field = 'Group' and ci.oldString = 'Triage' ) and (ci.field='assignee' and ci.newString is not NULL)
That means calculate time between: when the issue is assigned to group named Triage and when the issue is assigned to a person.
How can I fix it?
My SQL statement:
select TIMEDIFF(a.created,b.created)
from
(select g.created, g.issueid as groupid1
from changegroup g
join changeitem ci on (ci.groupid = g.id)
join jiraissue ji on (ji.id = g.issueid)
join project p on (p.id = ji.project)
join priority pr on (pr.id = ji.priority)
where ci.field = 'Group'
and ci.oldString = 'Triage'
and ci.field='assignee'
and ci.newString is not NULL
and p.pname = 'Test'
and pr.pname='P1'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
) a
left join (
select ji.created, ji.id as groupid2
from jiraissue ji
join changegroup g on (g.issueid = ji.id)
join project p on (p.id = ji.project)
where p.pname = 'Test'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
) b ON (a.groupid1 = b.groupid2);
This is the table from which I should retrieve data

See my comment about the quality of your question but a hint at how to solve this goes like (assuming you can make sure this doesn't create 1-n joins)
select groupid_orsomething_else, TIMEDIFF(a.created, b.created)
from yourtable
left join
(select groupid_orsomething_else, created
from yourtable
where field = 'Group' and oldstring is 'Triage'
) a
on a.groupid_orsomething_else = yourtable.groupid_orsomething_else
left join
(select groupid_orsomething_else, created
from yourtable
where field = 'assignee' and oldstring is null) b
on b.groupid_orsomething_else = yourtable.groupid_orsomething_else

Related

SSRS: Parameter not filtering MySQL query

I have a Date/Time parameter to my report:
But when I run my query, I get no results:
SELECT HD_QUEUE.NAME as qname, HD_TICKET.ID, HD_TICKET.CREATED, HD_TICKET.TIME_CLOSED, CUSTOMER.FULL_NAME as custfullname,
HD_STATUS.NAME as statname, HD_TICKET.TITLE, left(ASSIGNEE.FULL_NAME, 40) as assignee,
HD_PRIORITY.NAME as pname, HD_CATEGORY.NAME as catname
FROM HD_TICKET
INNER JOIN HD_QUEUE
ON HD_TICKET.HD_QUEUE_ID = HD_QUEUE.ID
INNER JOIN USER CUSTOMER
ON HD_TICKET.SUBMITTER_ID=CUSTOMER.ID
INNER JOIN USER ASSIGNEE
ON HD_TICKET.OWNER_ID=ASSIGNEE.ID
INNER JOIN HD_STATUS
ON (HD_TICKET.HD_STATUS_ID=HD_STATUS.ID)
AND (HD_TICKET.HD_QUEUE_ID=HD_STATUS.HD_QUEUE_ID)
INNER JOIN HD_PRIORITY
ON HD_TICKET.HD_PRIORITY_ID = HD_PRIORITY.ID
and HD_TICKET.HD_QUEUE_ID = HD_PRIORITY.HD_QUEUE_ID
INNER JOIN HD_CATEGORY
ON HD_TICKET.HD_CATEGORY_ID = HD_CATEGORY.ID
and HD_TICKET.HD_QUEUE_ID = HD_CATEGORY.HD_QUEUE_ID
left join ASSET on ASSET.ID = HD_TICKET.ASSET_ID
left join ASSET_DATA_6 on ASSET.ASSET_DATA_ID = ASSET_DATA_6.ID
WHERE (HD_STATUS.NAME = 'Closed'
AND HD_TICKET.TIME_CLOSED < #date_param);
What am I doing wrong?
MySQL does not allow named parameters. Use '?' instead of '#date_param' in the query.
WHERE (HD_STATUS.NAME = 'Closed'
AND HD_TICKET.TIME_CLOSED < ?;
Then check the Dataset Properties and make sure the '?' is associated with the value of your parameter:

How to Make This SQL Query More Efficient?

I'm not sure how to make the following SQL query more efficient. Right now, the query is taking 8 - 12 seconds on a pretty fast server, but that's not close to fast enough for a Website when users are trying to load a page with this code on it. It's looking through tables with many rows, for instance the "Post" table has 717,873 rows. Basically, the query lists all Posts related to what the user is following (newest to oldest).
Is there a way to make it faster by only getting the last 20 results total based on PostTimeOrder?
Any help would be much appreciated or insight on anything that can be done to improve this situation. Thank you.
Here's the full SQL query (lots of nesting):
SELECT DISTINCT p.Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(p.PostCreationTime) AS PostTimeOrder
FROM Post p
WHERE (p.Id IN (SELECT pc.PostId
FROM PostCreator pc
WHERE (pc.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pc.UserId = '100')
))
OR (p.Id IN (SELECT pum.PostId
FROM PostUserMentions pum
WHERE (pum.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pum.UserId = '100')
))
OR (p.Id IN (SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100'))
))
OR (p.Id IN (SELECT psm.PostId
FROM PostSMentions psm
WHERE (psm.StockId IN (SELECT sf.StockId
FROM StockFollowing sf
WHERE sf.UserId = '100' ))
))
UNION ALL
SELECT DISTINCT p.Id AS Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(upe.PostEchoTime) AS PostTimeOrder
FROM Post p
INNER JOIN UserPostE upe
on p.Id = upe.PostId
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND (uf.FollowingId = '100' OR upe.UserId = '100'))
ORDER BY PostTimeOrder DESC;
Changing your p.ID in (...) predicates to existence predicates with correlated subqueries may help. Also since both halves of your union all query are pulling from the Post table and possibly returning nearly identical records you might be able to combine the two into one query by left outer joining to UserPostE and adding upe.PostID is not null as an OR condition in the WHERE clause. UserFollowing will still inner join to UPE. If you want the same Post record twice once with upe.PostEchoTime and once with p.PostCreationTime as the PostTimeOrder you'll need keep the UNION ALL
SELECT
DISTINCT -- <<=- May not be needed
p.Id
, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime
, p.Content AS Content
, p.Bu AS Bu
, p.Se AS Se
, UNIX_TIMESTAMP(coalesce( upe.PostEchoTime
, p.PostCreationTime)) AS PostTimeOrder
FROM Post p
LEFT JOIN UserPostE upe
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND
(uf.FollowingId = '100' OR
upe.UserId = '100'))
on p.Id = upe.PostId
WHERE upe.PostID is not null
or exists (SELECT 1
FROM PostCreator pc
WHERE pc.PostId = p.ID
and pc.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pc.UserID
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM PostUserMentions pum
WHERE pum.PostId = p.ID
and pum.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pum.UserId
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM SStreamPost ssp
WHERE ssp.PostId = p.ID
and exists (SELECT 1
FROM SStreamFollowing ssf
WHERE ssf.SStreamId = ssp.SStreamId
and ssf.UserId = '100')
)
OR exists (SELECT 1
FROM PostSMentions psm
WHERE psm.PostId = p.ID
and exists (SELECT
FROM StockFollowing sf
WHERE sf.StockId = psm.StockId
and sf.UserId = '100' )
)
ORDER BY PostTimeOrder DESC
The from section could alternatively be rewritten to also use an existence clause with a correlated sub query:
FROM Post p
LEFT JOIN UserPostE upe
on p.Id = upe.PostId
and ( upe.UserId = '100'
or exists (select 1
from UserFollowing uf
where uf.FollwedID = upe.UserID
and uf.FollowingId = '100'))
Turn IN ( SELECT ... ) into a JOIN .. ON ... (see below)
Turn OR into UNION (see below)
Some the tables are many:many mappings? Such as SStreamFollowing? Follow the tips in http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
Example of IN:
SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (
SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100' ))
-->
SELECT ssp.PostId
FROM SStreamPost ssp
JOIN SStreamFollowing ssf ON ssp.SStreamId = ssf.SStreamId
WHERE ssf.UserId = '100'
The big WHERE with all the INs becomes something like
JOIN ( ( SELECT pc.PostId AS id ... )
UNION ( SELECT pum.PostId ... )
UNION ( SELECT ssp.PostId ... )
UNION ( SELECT psm.PostId ... ) )
Get what you can done of that those suggestions, then come back for more advice if you still need it. And bring SHOW CREATE TABLE with you.

Do I need a MySQL sub query? How can I get these results?

First, the table names and layouts:
Here are my desired results:
Here is the 'got ya' (trick) I guess..
I will only be passing a (dynamic) imis_id/user_id (col names currently not matching on one table)...
So a lookup (select) will need to be done on the relations table for that passed in (dynamic) id.. and where current_org = 1.
This will get/give me the target org_id in which I need to grab all user info (that are associated with the org_id).. and all org details.
Here is one weak/failed attempt: (it uses a hardcoded org_id) which is not valid.. I need to ONLY pass in the user_id/imis_id.. and where current_org = 1 to get the target org_id.
SELECT genealogy_orgs.org_id, genealogy_orgs.org_name,
genealogy_relations.user_id, genealogy_relations.relation_type, genealogy_relations.start_year, genealogy_relations.end_year,
genealogy_users.imis_id, genealogy_users.full_name
FROM genealogy_orgs
INNER JOIN genealogy_relations ON genealogy_orgs.org_id = genealogy_relations.org_id
INNER JOIN genealogy_users ON genealogy_relations.user_id = genealogy_users.imis_id
WHERE genealogy_orgs.org_id = '84864';
Here is another failed attempt (which only returns 1 row).. but uses the correct criteria:
SELECT
genealogy_relations.org_id,
genealogy_relations.user_id, genealogy_relations.relation_type, genealogy_relations.start_year, genealogy_relations.end_year,
genealogy_users.imis_id, genealogy_users.full_name,
genealogy_orgs.org_name
FROM genealogy_relations
INNER JOIN genealogy_orgs ON genealogy_relations.org_id = genealogy_orgs.org_id
INNER JOIN genealogy_users ON genealogy_relations.user_id = genealogy_users.imis_id
WHERE genealogy_relations.user_id = '00003' AND genealogy_relations.current_org = '1';
At this point, I'm not even sure what I need to search for? Is this where a 'sub-query/sub-select' comes into play?
My MySQL-fu is limited to very direct/plain-jane query types. This is getting to be more advanced than I am used to.
You need to join the genealogy_relations table with itself on org_id:
SELECT o.*, u.*
FROM genealogy_relations r1
JOIN genealogy_relations r2 ON r2.org_id = r1.org_id
JOIN genealogy_orgs o ON o.org_id = r2.org_id
JOIN genealogy_users u ON u.imis_id = r2.user_id
WHERE r1.user_id = '00003'
AND r1.current_org = '1'
Remove the genealogy_relations.user_id = '00003' from the query and it should work
SELECT
genealogy_relations.org_id,
genealogy_relations.user_id, genealogy_relations.relation_type, genealogy_relations.start_year, genealogy_relations.end_year,
genealogy_users.imis_id, genealogy_users.full_name,
genealogy_orgs.org_name
FROM genealogy_relations
INNER JOIN genealogy_orgs ON genealogy_relations.org_id = genealogy_orgs.org_id
INNER JOIN genealogy_users ON genealogy_relations.user_id = genealogy_users.imis_id
WHERE genealogy_relations.current_org = '1';

MySQL Joins where one value can be optional

Situation
I have a database which heavily makes use of joins due to the various situations in which each entity is used. Here is a simplified diagram:
Goal
I would like to be able to get details of all modules and the "name" fields regardless of whether the "fk_chapter_id" within user_has_module is set or not.
In the case where "user_has_module.fk_chapter_id" is null, the system can return details of the module and then null chapter.
In the case where there is a user_has_module, I would like to get the status
Issue
Whenever I perform SQL statements, I get the results only partially returned. I.E. If I have 4 module records in total, two of which where the user has an entry in "user_has_module" returns the two records in full and then 2 null records for the other modules.
Update based on feedback, almost there
Now, the only problem is I get duplicates. Using some test data
SELECT DISTINCT
chapter_id,
chapter_name,
module_id,
module_name,
(null ) AS user_module_progress,
(SELECT COUNT(fk_chapter_id) FROM module_has_chapter WHERE fk_module_id = m.module_id) AS chapter_count
FROM
module as m
LEFT JOIN
module_has_chapter as mhc ON m.module_id = mhc.fk_module_id
LEFT JOIN
chapter as c ON mhc.fk_chapter_id = c.chapter_id
group by m.module_id
UNION
SELECT DISTINCT
chapter_id,
chapter_name,
module_id,
module_name,
user_module_progress,
(SELECT COUNT(fk_chapter_id) FROM module_has_chapter WHERE fk_module_id = m.module_id) AS chapter_count
FROM
module as m
LEFT JOIN
user_has_module as uhm ON m.module_id = uhm.fk_module_id
LEFT JOIN
user as u ON uhm.fk_user_id = u.user_id
LEFT JOIN
chapter as c ON uhm.fk_latest_chapter_id = c.chapter_id
WHERE u.user_id = 2
group by m.module_id;
I got there in the end but, not particularly happy about it. This works but, it's a bloody mess...Does anyone have a better solution please?
SELECT DISTINCT
(null) AS chapter_id,
(null) AS chapter_name,
module_id,
module_name,
(null ) AS user_module_progress,
(SELECT COUNT(fk_chapter_id) FROM module_has_chapter WHERE fk_module_id = m.module_id) AS chapter_count
FROM
module as m
LEFT JOIN
user_has_module as uhm ON m.module_id = uhm.fk_module_id
WHERE
uhm.fk_user_id IS NULL
UNION ALL
SELECT DISTINCT
chapter_id,
chapter_name,
module_id,
module_name,
user_module_progress,
(SELECT COUNT(fk_chapter_id) FROM module_has_chapter WHERE fk_module_id = m.module_id) AS chapter_count
FROM
module as m
LEFT JOIN
user_has_module as uhm ON m.module_id = uhm.fk_module_id
INNER JOIN
user as u ON uhm.fk_user_id = u.user_id
INNER JOIN
chapter as c ON uhm.fk_latest_chapter_id = c.chapter_id
WHERE
u.user_id = 2;

problem with the result of a sql statement

I have the following scenario to achieve using SQL statement ,
I have an issue assigned to groups Triage,GX,GY:
group Triage --> group GX
group GX -->group Triage
group Triage --> group GY
I want to extract just the first time when my issue is assigned to group Triage and ignore the rest , I have tried to do that but always bad result(retrive all rows when the issue assigned to Triage group )
SQL Statement:
select g.created ,ji.pkey as issueName
from changegroup g
join changeitem ci on (ci.groupid = g.id)
join jiraissue ji on (ji.id = g.issueid)
join project p on (p.id = ji.project)
join priority pr on (pr.id = ji.priority)
where ci.field = 'Group'
and ci.oldString = 'Triage'
and p.pname = 'Test'
and pr.pname='P3'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
the result of the statement (as you see ,the issue 200 is assigned to group Triage 2 times so the request retrieve 2 rows):
The table changegroup has this structure:
The table changeitem has this structure:
Try this one. But it can be very slow query
select g.created, ji.pkey as issueName
from changegroup g
join jiraissue ji on (ji.id = g.issueid)
where (g.created, issueName) in (
select min(g.created) ,ji.pkey as issueName
from changegroup g
join changeitem ci on (ci.groupid = g.id)
join jiraissue ji on (ji.id = g.issueid)
join project p on (p.id = ji.project)
join priority pr on (pr.id = ji.priority)
where ci.field = 'Group'
and ci.oldString = 'Triage'
and p.pname = 'Test'
and pr.pname='P3'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
group by issueName
)