SQLite - Group by where more than x - sql

I've got three tables which relate to support ticket data for a software development firm, the tables are arranged like so:
Tickets
[PK]
ID Ticket_Type Type Created Resolved
s-100 s Bug 1434725860524 1463075456304
d-29 d Deployment 1434724333500 1463665757667
p-50 p Upgrade 1434722686876 1466575675677
s-25 s Training Issue 1434723799989 1465675675677
P-ticket_links
[PK]
Pticket Link
p-50 s-100
p-50 s-102
p-50 d-29
D-ticket_servers
[PK]
ID Server
d-29 Live Server
d-30 Test Server
d-31 Live Server
The primary key columns in the bottom two tables are also foreign keys which reference the ID column of the Tickets table.
For each p ticket of Type 'Upgrade', I need to find out the number of linked s tickets which were created after the resolved date of the linked d ticket, which itself is of Type 'Deployment' and which was carried out against the Live Server.
I've written a query to get the total number of s tickets linked to each Upgrade p ticket using a GROUP BY clause:
SELECT *,count(ts.id)
from [P-ticket_links] ptls
inner join [Tickets] ts on ts.ID=ptls.Link
inner join [Tickets] ts2 on ts2.ID=ptls.Pticket
where ts.Ticket_Type='s'
and ts2.Type='Upgrade'
group by ptls.Pticket
I can also find the resolved date of the Live Server Deployment d ticket for each p ticket using a similar query. However, what I'm having trouble doing is joining those two results together in order to exclude s tickets which were created before the resolved date of the Live Server Deployment d ticket.
I've tried creating another alias of the Tickets table, filtering it to contain the relevant d-tickets and then putting in a clause like WHERE tickets1.created > tickets3.resolved, but that didn't give me the right results.
I think what I need to do is essentially return a table in which every every row contains one s ticket linked to the corresponding p ticket as well as the resolved date for the d ticket linked to that p ticket. I could change my database structure to include the information in the first instance, but I don't want to denormalise my database any more and I feel like I should be able to do this with SQL.
Can anyone point me to how I could achieve this?

I've figured it out. This is how to return the results that I want:
select *,count(*) from [p-ticket_links] ptls
inner join
(SELECT
ts2.id as 'p-id',
ts.resolved as 'd-resolved'
FROM [tickets] ts
inner join [p-ticket_links] ptl on [ptl].link=ts.id
inner join [d-ticket_servers] dts on dts.id=ts.id
inner join [tickets] ts2 on ptl.pticket=ts2.id
inner join [p-ticket_versions] ptvs on ptvs.id=ts2.id
where [ts].type='Deployment'
and dts.server='Live Server'
and ts.summary like '%upgrade%'
and ts2.project_type='Upgrade'
and ts.state <> 'Duplicate') dres on dres.[p-id]=ptls.pticket
inner join [tickets] ts on ts.id=ptls.link
inner join [tickets] ts2 on ts2.id=ptls.pticket
where ts.ticket_type='S'
and ts2.project_type='Upgrade'
and ts.created > dres.[d-resolved]
group by ptls.pticket

Related

Postgres Join 3 Tables(Timestamp)

I have 3 tables and need mutliple values from them. I need pname(project), lead(project), author(changegroup) and updated(jiraissue)/created(changegroup). pname and lead are project name and leader of the project. Author is the one who changed the ticket the last time, and update and created are the timestamps from that action. But update and created are often not the same. So cant use them to filter. I have no problem to get pname, lead, and update. But I need the author too.
SELECT pname, lead, MAX(updated) FROM project join jiraissue on project.id=jiraissue.project GROUP BY(pname, lead);
That is the query command to get pname, lead, and updated. I filter the all tickets from a project, and look which was edited the most recently. I take that timestamp for the time the entire project was edited the last time. But couldn't create an command to get the author too. you help me?
Project Table:
The Project itself with project name and lead| public.id=jiraissue.project
Jira Issue Table:
jiraissues are all tickets from the projects |project.id=jiraissue.project, jiraissue.updated is most times changegroup.created, changegroup.issueid=jiraissue.id
Changegroup Table:
changegroup is a list of the times when a ticket is edited| changegroup.issueid=jiraissue.id, changegroup.created=jiraissue.updated
Your explanation left me confused. But here is my educated guess:
SELECT p.pname, p.lead, c.author, j.updated, c.created
FROM project p
LEFT JOIN (
SELECT DISTINCT ON (j.project)
j.project, j.updated, j.id
FROM jiraissue j
ORDER BY j.project, j.updated DESC NULLS LAST
) j ON j.project = p.id
LEFT JOIN changegroup c ON c.issueid = j.id;
Another case for DISTINCT ON. See:
Select first row in each GROUP BY group?
Eliminating unneeded rows before joining should be the fastest way.
I use 2x LEFT JOIN retain projects without any Jira issues in the result.

A count of something inside an INNER JOIN?

Let's say I had a table of machines our employees use called machineManufacturer, which had the columns ID, and manufacturer. Then, I had another table that was added to whenever that machine was used called deviceUsage, which has the columns ID, and date.
I want to know the number of times used grouped according to manufacturer.
I believe the answer has something to do with COUNT and an INNER JOIN, but I am fairly new to SQL (only took one databases class in school).
I have tried something like:
SELECT manufacturer
FROM machineManufacturer
INNER JOIN deviceUsage
ON machineManufacturer.ID = deviceUsage.ID
which returns a big column of manufacturers, without any count. I am trying to count them and get a table like--
Manufacturer: Count
Dell: 30
HP: 27
Mac: 9
Lenovo: 14
etc.
Any comments welcome. Thank you for your time.
I think you want group by:
SELECT MF.manufacturer, count(*)
FROM machineManufacturer MF INNER JOIN
deviceUsage D
ON MF.ID = D.ID
GROUP BY MF.manufacturer;

Query two tables linked to same primary key

long time reader first time poster.
I have what looks like a straight forward Access question.
I've an Employee table with these fields;
|EmployeeID|StaffName|Phone|Email|
EmployeeID is a foreign key in two tables - one for logging the status of a generator ie
|LogID|Status|Logged By|
and one for any incidents with the generator
|IncidentID|Description|Raised By|LogID|
I can create a query to link incidents and their log details eg
|IncidentID|Description|Raised By|LogID|Logged By|
This works if I put the EmployeeID number into 'Logged By' and 'Raised By' - if I put the StaffName - as the company wants, it doesn't work because it's selecting two StaffNames from the same primary key.
Any way around this?
Here is the Access code, the part where LoggedBy and RaisedBy are joined to EmployeeID is in bold.
SELECT [2_Incidents].IncidentID, [2_Incidents].Description, [8_Employees].StaffName AS [Raised By], [1_Log].LogID, [8_Employees].StaffName AS [Logged By]
FROM 8_Employees INNER JOIN (2_Incidents INNER JOIN 2_Incidents ON [1_Log].LogID = [2_Incidents].LogID) ON [8_Employees].EmployeeID = [1_Log].LoggedBy AND [8_Employees].EmployeeID = [2_Incidents].RaisedBy);
I've gotten around this by creating a copy of the Employees table but this could get awkward if there are more fields linked to Employees in the future (eg Closed By, Verified By etc)
If I understand you correctly, the solution is to join to the employee table twice.
In your log details you are doing something like SELECT * FROM incident JOIN log USING (LogID)...
You mention "selecting two StaffNames from the same primary key" - I take it that you are attempting to join Employee somehow with Raised By and Logged By.
If you actually join to two copies of employee: SELECT ... FROM incident JOIN log USING (LogId) JOIN employee ei ON (ei.employeeid = incident.raised_by) JOIN employee el ON (el.employeeid = log.logged_by) you can reference then the ei.staffname (incident raise by employee) and el.staffname (logged by employee)
PS. Sorry about the non-access syntax, but hopefully you can convert!

Needing 2 different ID's from the same ID Table

I am pulling reports for my company and am needing to pull a specific report that I am having trouble with. We are using SQL Server 2012 and I am pulling the SQL reports.
What I need is to pull a simple report:
Group Name, List of Members in the group; Supervisor of the group.
However, the problem is that the supervisor as well as the members and the group name all come from one table in order to get the relevant information. Currently here is my SQL code below:
Use DATABASE
go
-- This is the select portion deciding the columns needed.
select
C.group_name
,C2.first_name
,C2.last_name
-- These are the tables that the query is pulling from.
FROM db..groups AS G
LEFT OUTER JOIN db..contact AS C
ON G.group_id=C.contact_id
INNER JOIN db..contact AS C2
ON G.member=C2.contact_id
go
This pulls the first portion:
The group name, then the first name of a member in that group, and then the last name of a member in that group.
However, I am having trouble getting the supervisor portion. This portion uses the table db.contact under the column supervisor_id as a foreign key. The supervisor_id uses the same unique id as the normal contact_id, but in the same table. Some contact_ids have supervisor_id's that are other contact_id's from the same table, hence the foreign key.
How can I make it so I can get the contact_id that is equal to the supervisor_id of the contact_id that is equal to the group_id?
Taking a quick stab at this while we wait for details
You know you need groups and I'm assuming you don't care about Groups that have no members. Thus Groups INNER JOINed to Contact. This generates your direct group membership. To get the supervisor, you then need to factor in the Supervisor on the specific Contact row.
You might not have a boss, or your boss might be yourself. It's always interesting to see how various HR systems record this. In my example, I'm assuming the head reports to no one instead of themselves.
SELECT
G.group_name
, C.first_name
, C.last_name
-- this may produce nulls depending on outer vs inner join below
, CS.first_name AS supervisor_first_name
, CS.last_name AS supervisor_last_name
FROM
dbo.Groups AS G
INNER JOIN
dbo.Contact AS C
ON C.contact_id = G.member
LEFT OUTER JOIN
dbo.Contact AS CS
ON CS.contact_id = C.supervisor_id;
Depending on how exactly you wanted that data reported, there are various tricks we could use to report that data. In particular, GROUPING SETS might come in handy.
SQLFiddle

Uses of unequal joins

Of all the thousands of queries I've written, I can probably count on one hand the number of times I've used a non-equijoin. e.g.:
SELECT * FROM tbl1 INNER JOIN tbl2 ON tbl1.date > tbl2.date
And most of those instances were probably better solved using another method. Are there any good/clever real-world uses for non-equijoins that you've come across?
Bitmasks come to mind. In one of my jobs, we had permissions for a particular user or group on an "object" (usually corresponding to a form or class in the code) stored in the database. Rather than including a row or column for each particular permission (read, write, read others, write others, etc.), we would typically assign a bit value to each one. From there, we could then join using bitwise operators to get objects with a particular permission.
How about for checking for overlaps?
select ...
from employee_assignments ea1
, employee_assignments ea2
where ea1.emp_id = ea2.emp_id
and ea1.end_date >= ea2.start_date
and ea1.start_date <= ea1.start_date
Whole-day inetervals in date_time fields:
date_time_field >= begin_date and date_time_field < end_date_plus_1
Just found another interesting use of an unequal join on the MCTS 70-433 (SQL Server 2008 Database Development) Training Kit book. Verbatim below.
By combining derived tables with unequal joins, you can calculate a variety of cumulative aggregates. The following query returns a running aggregate of orders for each salesperson (my note - with reference to the ubiquitous AdventureWorks sample db):
select
SH3.SalesPersonID,
SH3.OrderDate,
SH3.DailyTotal,
SUM(SH4.DailyTotal) RunningTotal
from
(select SH1.SalesPersonID, SH1.OrderDate, SUM(SH1.TotalDue) DailyTotal
from Sales.SalesOrderHeader SH1
where SH1.SalesPersonID IS NOT NULL
group by SH1.SalesPersonID, SH1.OrderDate) SH3
join
(select SH1.SalesPersonID, SH1.OrderDate, SUM(SH1.TotalDue) DailyTotal
from Sales.SalesOrderHeader SH1
where SH1.SalesPersonID IS NOT NULL
group by SH1.SalesPersonID, SH1.OrderDate) SH4
on SH3.SalesPersonID = SH4.SalesPersonID AND SH3.OrderDate >= SH4.OrderDate
group by SH3.SalesPersonID, SH3.OrderDate, SH3.DailyTotal
order by SH3.SalesPersonID, SH3.OrderDate
The derived tables are used to combine all orders for salespeople who have more than one order on a single day. The join on SalesPersonID ensures that you are accumulating rows for only a single salesperson. The unequal join allows the aggregate to consider only the rows for a salesperson where the order date is earlier than the order date currently being considered within the result set.
In this particular example, the unequal join is creating a "sliding window" kind of sum on the daily total column in SH4.
Dublicates;
SELECT
*
FROM
table a, (
SELECT
id,
min(rowid)
FROM
table
GROUP BY
id
) b
WHERE
a.id = b.id
and a.rowid > b.rowid;
If you wanted to get all of the products to offer to a customer and don't want to offer them products that they already have:
SELECT
C.customer_id,
P.product_id
FROM
Customers C
INNER JOIN Products P ON
P.product_id NOT IN
(
SELECT
O.product_id
FROM
Orders O
WHERE
O.customer_id = C.customer_id
)
Most often though, when I use a non-equijoin it's because I'm doing some kind of manual fix to data. For example, the business tells me that a person in a user table should be given all access roles that they don't already have, etc.
If you want to do a dirty join of two not really related tables, you can join with a <>.
For example, you could have a Product table and a Customer table. Hypothetically, if you want to show a list of every product with every customer, you could do somthing like this:
SELECT *
FROM Product p
JOIN Customer c on p.SKU <> c.SSN
It can be useful. Be careful, though, because it can create ginormous result sets.