DISTINCT key word issues in SQLite - sqlite

Trying to run a query that should bring back all mechanics and a sum of all their commissions from another table but only getting one mechanics name and a sum of all commissions. Tried writing the query in different ways but getting the same result.
The Query:
SELECT DISTINCT m.mechID, fname || ' ' || lname AS 'Full Name', SUM(commission) AS 'Total Commissions Per Mechanic'
FROM
mechanics AS m
INNER JOIN mech_commissions AS mc on m.mechID = mc.mechID
ORDER BY "Full Name";
The output:

I think you want an aggregation query here:
SELECT m.mechID, m.fname || ' ' || m.lname AS `Full Name`,
SUM(mc.commission) AS `Total Commissions Per Mechanic`
FROM mechanics AS m
INNER JOIN mech_commissions AS mc ON m.mechID = mc.mechID
GROUP BY 1, 2
ORDER BY `Full Name`;

Related

Cannot replace a string with several random strings taken from another table in sqlite

I'm trying to replace a placeholder string inside a selection of 10 random records with a random string (a name) taken from another table, using only sqlite statements.
i've done a subquery in order to replace() of the placeholder with the results of a subquery. I thought that each subquery loaded a random name from the names table, but i've found that it's not the case and each placeholder is replaced with the same string.
select id, (replace (snippet, "%NAME%", (select
name from names
where gender = "male"
) )
) as snippet
from imagedata
where timestamp is not NULL
order by random()
limit 10
I was expecting for each row of the SELECT to have different random replacement every time the subquery is invoked.
hello i'm %NAME% and this is my house
This is the car of %NAME%, let me know what you think
instead each row has the same kind of replacement:
hello i'm david and this is my house
This is the car of david, let me know what you think
and so on...
I'm not sure it can be done inside sqlite or if i have to do it in php over two different database queries.
Thanks in advance!
Seems that random() in the subquery is only evaluated once.
Try this:
select
i.id,
replace(i.snippet, '%NAME%', n.name) snippet
from (
select
id,
snippet,
abs(random()) % (select count(*) from names where gender = 'male') + 1 num
from imagedata
where timestamp is not NULL
order by random() limit 10
) i inner join (
select
n.name,
(select count(*) from names where name < n.name and gender = 'male') + 1 num
from names n
where gender = 'male'
) n on n.num = i.num

Counting 2 Columns from Separate Tables Between 2 Dates

I have a query that Counts 2 columns from 2 separate tables using subqueries, which works. Now I have to implement into this query the ability to filter out these results based on the Date of a Call Record. I will post the query in which I am working with:
SELECT (m.FirstName || " " || m.LastName) AS Members,
(
SELECT count(CallToLineOfficers.MemberID)
FROM CallToLineOfficers
WHERE CallToLineOfficers.MemberID = m.MemberID
)
+ (
SELECT count(CallToMembers.MemberID)
FROM CallToMembers
WHERE CallToMembers.MemberID = m.MemberID
) AS Tally
FROM Members AS m, Call, CallToMembers, CallToLineOfficers
Join Call on CallToMembers.CallID = Call.CallID
and CallToLineOfficers.CallID = Call.CallI
WHERE m.FirstName <> 'None'
-- and Call.Date between '2017-03-21' and '2017-03-22'
GROUP BY m.MemberID
ORDER BY m.LastName ASC;
Ok, so table Call stores the Date and its PK is CallID. Both CallToLineOfficers and CallToMembers are Bridge Tables that also contain only CallID and MemberID. With the current query, where the Date is commented out, that Date range should only return all names, but a count of 1 should appear under 1 person's name.
I have tried joining Call.CallID with both Bridge Tables' CallIDs without any luck, though I think this is the right way to do it. Could someone help point me in the right direction? I am lost. (I tried explaining this the best I could, so if you need more info, let me know.)
UPDATED: Here is a screenshot of what I am getting:
Based on the provided date in the sample, the new results, with the Date, should be:
Bob Clark - 1
Rob Catalano - 1
Matt Butler - 1
Danielle Davidson - 1
Jerry Chuska - 1
Tom Cramer - 1
Everyone else should be 0.
At the moment, the subqueries filter only on the member ID. So for any member ID in the outer query, they return the full count.
To reduce the count, you have to filter in the subqueries:
SELECT (FirstName || " " || LastName) AS Members,
(
SELECT count(*)
FROM CallToLineOfficers
JOIN Call USING (CallID)
WHERE MemberID = m.MemberID
AND Date BETWEEN '2017-03-21' AND '2017-03-22'
)
+ (
SELECT count(*)
FROM CallToMembers
JOIN Call USING (CallID)
WHERE MemberID = m.MemberID
AND Date BETWEEN '2017-03-21' AND '2017-03-22'
) AS Tally
FROM Members AS m
WHERE FirstName <> 'None'
ORDER BY LastName ASC;

SQLite Join Causing Duplicate Data After First Correct Record

I am having an issue where after the first record in a Select statement the data in a certain column is being duplicated within the Select statement. I will provide the statement in which I am working with:
SELECT Call.CallID AS [Call #],
(Members.FirstName || ' ' || Members.LastName) AS OIC,
Alarm.AlarmID,
Alarm.AlarmDesc AS Alarm,
--Group_Concat(m2.FirstName || ' ' || m2.LastName) AS [Line Officers],
Group_Concat(m1.FirstName || ' ' || m1.LastName) AS Members
FROM Call
LEFT JOIN
Members ON Call.OIC = Members.MemberID
LEFT JOIN
Alarm ON Call.AlarmID = Alarm.AlarmID
LEFT JOIN
CallToMembers ON Call.CallID = CallToMembers.CallID
--LEFT JOIN
--CallToLineOfficers on Call.CallID = CallToLineOfficers.CallID
LEFT JOIN
Members AS m1 ON CallToMembers.MemberID = m1.MemberID
--LEFT JOIN
--Members as m2 on CallToLineOfficers.MemberID = m2.MemberID
GROUP BY Call.CallID;
Ok, so this statement returns everything that I need and is working perfectly. However, whenever I uncomment the lines that are commented out so that I can obtain "Line Officers" from the Bridge Table "CallToLineOfficers", data begins to duplicate from within the columns like so:
Incorrect Complete Select Statement
- Nothing commented out.
Correct Line Officers
- If I comment Joins for CallToMembers.
Correct Members
- If I comment Joins for CallToLineOfficers.
As you can see that once I introduce both "Members" and "Line Officers", things go wrong.
When you join the calls with the line officers, you get an intermediate result like this:
Call # Line Officers
------ -------------
54 Bob Clark
54 Rob Catalano
When you then join with the members, the database matches the call number again, so for each row in the intermediate result, you get all combinations with the members:
Call # Line Officers Members
------ ------------- -----------
54 Bob Clark Matt Butler
54 Rob Catalano Matt Butler
54 Bob Clark Tom Cramer
54 Rob Catalano Tom Cramer
...
So you cannot use joins when you have multiple independent tables with 1:N relationships.
You don't actually want to have multiple line officer/member rows in the result anyway, so you can just use a subquery to aggregate those values:
SELECT CallID,
(SELECT group_concat(FirstName || ' ' || LastName)
FROM CallToLineOfficers
JOIN Members USING (MemberID)
WHERE CallID = Call.CallID
) AS "Line Officers",
(SELECT group_concat(FirstName || ' ' || LastName)
FROM CallToMembers
JOIN Members USING (MemberID)
WHERE CallID = Call.CallID
) AS Members
FROM Call;

Column Relationships

I realize i'm far off the solution with what i have:
Select FirstName || ' ' || LastName AS Manager From Employee
Where (Select COUNT(ReportsTo) from Employee
group by ReportsTo
order by ReportsTo desc);
ReportsTovalues are the EmployeeID they report to
What i want is to query the name of the employee with the most Employees reporting to them and who they in turn report to without nulls. I'm Not sure how to make the connections between columns values such as ReportsTo to EmployeeID so any explanation would help
For Example the output i would want is two columns say | Fred Jones | Mary Anne| the first being the employee with the most reportsTo with the same value as their EmployeeID and the second being the name of the employee with the same EmployeeID as the first employees ReportTo
Do this step by step:
First step: Count how many employees report to a person.
select reportsto, count(*) from employee group by reportsto;
We can order this result by count(*) and limit it to only get one row, so as to get the person with the most reporters. Only problem is: What to do in case of ties, i.e. two persons have the same highest amount of reporters? SQLite doesn't offer much to help here. We'll have to query twice:
select reportsto
from employee
group by reportsto
having count(*) =
(
select count(*)
from employee
group by reportsto
order by count(*) desc
limit 1
);
Next step: Get the name. That means we must access the table again.
select
firstname || ' ' || lastname as manager
from employee
where e1.employeeid in
(
select reportsto
from employee
group by reportsto
having count(*) =
(
select count(*)
from employee
group by reportsto
order by count(*) desc
limit 1
)
);
Last step: Get the persons our found managers themselves report to. These can be many, so we group by manager and concatenate all those they report to.
select
e1.firstname || ' ' || e1.lastname as manager,
group_concat(e2.firstname || ' ' || e2.lastname) as reportsto
from employee e1
join employee e2 on e2.employeeid = e1.reportsto
where e1.employeeid in
(
select reportsto
from employee
group by reportsto
having count(*) =
(
select count(*)
from employee
group by reportsto
order by count(*) desc
limit 1
)
)
group by e1.firstname || ' ' || e1.lastname;
SELECT e.ReportsTo AS TopManagersEmployeeId, COUNT(e.ReportsTo) AS ReportedBy, m.FirstName + ' ' + m.LastName AS TopManagersName, mm.FirstName + ' ' + mm.LastName AS TheirManagersName FROM Employees e
JOIN Employees m
ON e.ReportsTo = m.EmployeeID
JOIN Employees mm
ON m.ReportsTo = mm.EmployeeID
GROUP BY e.ReportsTo, m.FirstName, m.LastName, mm.FirstName, mm.LastName
Once you have this data, you can do TOP 1 etc. You can also play around with JOIN, and make it INNER JOIN in the second set where Manager's Manager (mm) is being retrieved.

GROUP BY / Aggreggate function clarification

I have an SQL Query for each of my 2 Gridview elements. One is getting all the transactions by branch and transaction date:
SELECT
tb_TransactionDetails.TxnID,
tb_TransactionDetails.BranchCode,
tb_TransactionDetails.TxnDate,
tb_TransactionDetails.ReferenceNo,
tb_TransactionType.TxnTypeName,
tb_CurrencyCode.CCYDesc,
tb_TransactionDetails.CCYAmount,
tb_RecordStatus.StatusDesc,
(tb_TransactionName.FirstName + ' ' + ISNULL(tb_TransactionName.MiddleName,'') + ' ' + ISNULL(tb_TransactionName.LastName,'')) as 'Client',
(tb_TransactionName.AddressLine1 + ' ' + ISNULL(tb_TransactionName.AddressLine2, '') + ' ' + ISNULL(tb_TransactionName.AddressLine3, '')) as 'Address',
tb_TransactionName.WhoAdded,
tb_TransactionName.DateAdded,
ROW_NUMBER() OVER
(ORDER BY BranchCode ) AS RowNumber
FROM (((tb_TransactionType inner join tb_TransactionDetails
on tb_TransactionType.TxnTypeCode = tb_TransactionDetails.TxnType)
INNER JOIN tb_CurrencyCode on tb_TransactionDetails.CCYCode = tb_CurrencyCode.CCYCode)
inner join tb_RecordStatus on tb_TransactionDetails.RecordStatus = tb_RecordStatus.StatusCode)
LEFT JOIN tb_TransactionName
on tb_TransactionDetails.TxnID = tb_TransactionName.TxnID
WHERE BranchCode = '1003'
and TxnDate = '12/13/2013'
and one is getting all the users in the system:
select
USR.UserName,
USR.BranchID,
(ISNULL(USR.FirstName,'') + ' ' + ISNULL((SUBSTRING(USR.MiddleName,1,1) + '.' ),'') + ' ' + ISNULL(USR.LastName,'')) as 'Name',
MBS.IsLockedOut,
USR.LastActivityDate,
MAX(STUFF(fxMerge.RoleId, 1, 2, '')) as 'Roles'
from (aspnet_Membership as MBS inner join aspnet_Users as USR
on USR.ApplicationId = USR.ApplicationId and MBS.UserId = USR.UserId)
inner join aspnet_UsersInRoles UIR
on USR.UserId = UIR.UserId
CROSS APPLY(
SELECT ', ' + RoleName
FROM aspnet_UsersInRoles UIR1
INNER JOIN aspnet_Roles RM ON UIR1.RoleId = RM.RoleID
WHERE UIR.UserId = UIR1.UserId
FOR XML PATH('')) fxMerge (RoleId)
where USR.UserName = 'JSmith'
group by USR.UserName, USR.BranchID, USR.FirstName, USR.MiddleName, USR.LastName, MBS.IsLockedOut, USR.LastActivityDate
one thing I'm confused about, is that the 1st query does not need a GROUP BY clause, while the 2nd one does. My question is, why? I've been running the 1st query hundreds of times no problem in my system, without ever having the need of a GROUP BY clause, and the Gridview displays the expected results. While on my 2nd query, It's only when I add the long GROUP BY clause that the query executes successfully on the SQL Server Management studio, then nothing shows up on my Gridview.
That's because your second query has a MAX(). If you want the highest or lowest value, or the count or any other aggregate function, you'll need to specify how to group it.

Resources