SQL Counting Calls from other tables - mysql

Having trouble counting from a separate table. I'm only getting how many callers are making calls rather than each individual count for every call.
I have went in and checked that most callers make multiple calls but i'm not sure how to show this.
I'm looking for which Company has >18 calls.
Tables are:
Customer
Company_ref
Company_name
Contact_id
Address_1
Address_2
Caller
Caller_id
Company_ref
First_name
Last_name
Issue
Call_ref
Caller_id
Call_date
Detail
Query:
SELECT Company_name, Count(Call_ref)
from Customer JOIN Issue on (Contact_id = Caller_id)
Group by Company_name
and example of the outcome is
Affright Retail 5
Askew Inc. 5
Askew Shipping 6
Bai Services 2
Cell Group 5
Comfiture Traders 5
which is only counting how many callers rather than how many calls made

This should work (MS SQL-Server):
select a.Company_ref, count(c.Call_ref) as Calls from caller a
join Issue b on (a.Caller_id = b.Caller_id)
join Customer c on (a.Company_ref = c.Company_ref)
group by a.Company_ref
adding a Where clause to determine companies with 18 or more calls:
select * from (
select a.Company_ref, count(c.Call_ref) as Calls from caller a
join Issue b on (a.Caller_id = b.Caller_id)
join Customer c on (a.Company_ref = c.Company_ref)
group by a.Company_ref ) result
where Calls > 18

CallerID refers to Caller table not Customer table
SELECT Y.Company_name, Count(I.Call_ref)
FROM Issue I
JOIN Customer C
ON I.Caller_id = C.Caller_id
JOIN Company Y
ON C.Company_ref = Y.Company_ref
Group by Company_name

Related

Sql to fetch records only if related other table records exist

Table: user
id
compId
1
comp1
2
comp1
Table: Company
id
name
comp1
coke
comp2
pepsi
need a MYSQL query which should fetch company record only if it has one or more users, when passed a company id. I will have other where conditions on company table.
Can this be achieved by joins?
example 1: query(comp1) result: coke (atleast one user exists)
example 2: query(comp2) result: no records (Since no user exists who belong to company comp2)
What you're asking for is called a semi-join. This returns one row from company if there are one or more matching rows in user.
If you use a regular join:
SELECT c.* FROM company c JOIN user u ON u.compid = c.id;
This does return the row from company, but you might not like that it returns one row per user. I.e. rows in the result are multiplied by the number of matches.
There are several possible fixes for this, to reduce the results to one row per company.
SELECT DISTINCT c.* FROM company c JOIN user u ON u.compid = c.id;
SELECT c.* FROM company c JOIN (SELECT DISTINCT compid FROM user) u ON u.compid = c.id;
SELECT * FROM company c WHERE c.id IN (SELECT compid FROM user);
SELECT * FROM company c WHERE EXISTS (SELECT * FROM user WHERE compid = c.id);
Which one is best for your app depends on many factors, such as the sizes of the tables, the other conditions in the query, etc... I'll leave it to you to evaluate them given your specific needs.

SQL Query, LEFT JOINs with NULLs

I am trying to create a list of hours by Company and Date, even if the Company does not have data for that Date. I've tried LEFT JOINing a Calendar table and Grouping on its dates and then Company, but to no avail.
SELECT cal.date, comp.name, comp.hours
FROM company AS comp
LEFT JOIN calendar AS cal ON cal.date=comp.date
GROUP BY cal.date, comp.name
I expect to get NULL outputs when a Company does not have hours for that Date, like so:
2018-01-01 Company A 100
2018-01-01 Company B NULL
2018-01-02 Company A NULL
2018-01-02 Company B NULL
2018-01-03 Company A 100
2018-01-03 Company B 50
But it only returns rows where data can be found, as if I used an INNER JOIN. Any help would be appreciated. Thank you!
You've made 3 mistakes, of which 2 are relevant:
You swapped the order of the tables in the join (easy to fix)
Your query does not reflect your stated intent (harder to fix)
You are using GROUP BY when it is unnecessary (irrelevant in this particular case)
I'll focus on 2. You're close to your goal but not all there. Fixing the first and third mistakes, here is your query:
SELECT cal.date, comp.name, comp.hours
FROM calendar AS cal
LEFT JOIN company AS comp ON cal.date=comp.date
This is going to do something like the following:
For each cal_row in calendar:
For each comp_row in company:
If cal_row.date equals comp_row.date:
Create output row and append to output
If no rows created:
Create output row, fill with NULLs, and append to output
So your query guarantees at least 1 output row per date. What you are looking for is 1 output row per date, per company. One way to do this is by creating an intermediate table, and left-joining to that:
SELECT tbl.date, tbl.name, comp.hours
FROM (
SELECT DISTINCT cal.date, comp.name
FROM calendar AS cal
CROSS JOIN company as comp
) AS tbl
LEFT JOIN LEFT JOIN company AS comp ON
tbl.date = comp.date AND tbl.name= comp.name
http://sqlfiddle.com/#!9/517b4e/11/0
This matches your desired output.
you can use calendar as a left table,in that case you will get all the date
SELECT cal.date, comp.name, comp.hours
FROM calendar AS cal
LEFT JOIN company AS comp ON cal.date=comp.date
I have not found any aggregate function so i removed group by

Marking Records as duplicates in mySQL

I am not a databases guy,but I have been given the "fun" job of cleaning up someone else's database. We have many duplicate record in our databases and some of customers are getting double or triple billed every month.
Given the following Database example
:
Table: Customers
ID Name Phone DoNotBill
1 Acme Inc 5125551212 No
2 ABC LLC 7138221661 No
3 Big Inc 4132229807 No
4 Acme 5125551212 No
5 Tree Top 2127657654 No
Is it possible to write a query that Identifies the all duplicate phone numbers (in this case records 1 and 4) and then marks and duplicate records yes by updating the DoNotBill column. But leaves the first record unmarked.
In this example case we would be left with:
ID Name Phone DoNotBill
1 Acme Inc 5125551212 No
2 ABC LLC 7138221661 No
3 Big Inc 4132229807 No
4 Acme 5125551212 Yes
5 Tree Top 2127657654 No
something like this?
UPDATE
customers cust,
(SELECT
c1.ID,
c1.name,
c1.phone,
c1.DoNotBill
FROM customers c
LEFT JOIN
(SELECT
cc.ID
FROM customers cc
) as c1 on c1.phone = c.phone
) dup
SET cust.DoNotBill = 'Yes' WHERE cust.id=dup.id ;
To begin with I assume that the DoNotBill column only has two possible values; yes and no. In that case it should be bool instead of varchar, meaning it would be either true or false.
Furthermore I don't get the meaning of the DoNotBill column. Why wouldn't you just use something like this?
select distinct phone from customers
SQL SELECT DISTINCT
That would give you the phone numbers without duplicates and without the need for an extra column.
This depends on ur data amount
You can do it in steps and make use some tools like excel...
This qrt
SELECT a.id,b.id,a.phone FROM clients a , clients b WHERE
A.phone =b.phone
And a.id!=b.id
The result is all duplicated records.
Add
Group by a.phone
And u will get 1 record for each 2 duplicates.
if you like the records and they are whT u need. ChNge select to select a.id and
Use this qry as subqry to an update sql statement
UPDATE clients SET billing='no' WHERE id IN ( sql goes here)
UPDATE customers c SET c.DoNotBill="Yes";
UPDATE customers c
JOIN (
SELECT MIN( ID ) ID, Phone
FROM customers
GROUP BY Phone
) u ON c.ID = u.ID AND c.Phone = u.Phone
SET c.DoNotBill="No";
That way not only duplicates are eliminated, but all multiple entries are dealt with.

Optimize complex MySQL selects for reporting

I'm building an application in which,
a) each librarian can create a campaign
b) actions carried out as part of that campaign are tracked in campaign_actions, actions being page loads
In order to report on the number of actions made in each campaign, I wrote this SQL query (for MySQL) for the following database structure, with the intention of tracking the number of actions undertaken by a librarian for each campaign:
LIBRARIANS
id | status
CAMPAIGNS
id | librarian_id
CAMPAIGN_ACTIONS
id | campaign_id | name
The problems I am having are:
a) I have to specify the fields I want to count in the correlated subselects
b) The query will be quite expensive as a result
My question is, since there are multiple actions for a campaign, how can I effectively count the number of actions per campaign in a more efficient manner?
Less complex queries amount to returning a result set like so:
librarians.id | librarians.status | campaign_actions.name
1 3 pageX
1 3 pageY
1 3 pageZ
1 3 pageA
1 3 pageB
2 3 pageX
which means i'd have to parse the result set in application code row by row, which is likely to be more expensive.
I appreciate any thoughts you may have on this problem.
Breaking the task into smaller tasks (views):
--- campaings per librarian
CREATE VIEW count_librarian_campaigns
AS ( SELECT lib.id AS lib_id
, COUNT(c.id)
AS num_campaigns
FROM librarians lib
LEFT JOIN campaigns c
ON c.librarian_id = lib.id
GROUP BY lib.id
)
--- campaign actions per campaign
CREATE VIEW count_campaign_actions
AS ( SELECT c.id AS c_id
, COUNT(ca.campaign_id)
AS num_actions
FROM campaigns c
LEFT JOIN campaign_actions ca
ON ca.campaign_id = c.id
GROUP BY c.id
)
So, you could have queries like this:
SELECT lib.id AS lib_id
, countlibc.num_campaigns
, c.id AS c_id
, countca.num_actions
FROM librarians lib
JOIN count_librarian_campaigns countlibc
ON countlibc.lib_id = lib.id
LEFT JOIN campaigns c
ON c.librarian_id = lib.id
JOIN count_campaign_actions countca
ON countca.c_id = c.id
Does something like this work for your purposes?
SELECT librarians_id,COUNT(librarians_id) FROM (
SELECT librarians.id as librarians_id,
librarians.status as librarians_status,
campaign_actions.name as campaign_actions_name
FROM campaign_actions
INNER JOIN campaigns
ON campaign_actions.campaign_id = campaigns.id
INNER JOIN librarians
ON campaigns.librarian_id = librarians.id
GROUP BY campaign_actions.name,librarians.id,librarians.status ) as a
Maybe I misunderstood what you're after. The inner query seems like it would return the table you represented above.

mysql search - return id only if it's present in all of the conditions

I have a yable for members and a table for the services that each member provides:
MemberID | ServiceID
--------------
1 | 2
1 | 3
2 | 1
2 | 3
So a member can provide any number of services.
I have a search form which lets the user check some or all of the services. I want to be able to select all of the members that provides ALL of the services that the user selected (and not just some of them). I used WHERE ... IN.., but it returns all of the members that provides at least one of the selected services.
I now have a query similar to:
SELECT members.id
FROM
members
LEFT JOIN services ON (members.id=services.memberID)
WHERE members.id IN (....)
Any help?
Thank you
If I understand your question correctly, this should work:
SELECT memberID
FROM services
WHERE ServiceID IN (...)
GROUP BY memberID
HAVING COUNT(*) = x;
where (...) is a list of all the selected servicesIDs, and x is the number of items in (...)
The problem seems to be the LEFT join and the fact you are checking members.id in the where clause ("select all of the members that provides ALL of the services that the user selected", so you should be checking on servicesID):
SELECT members.id
FROM
members
JOIN services ON (members.id=services.memberID)
WHERE servicesID IN (....)
I actually use a variation of this question when I do interviews (thanks for coming in, Mr Ant, we will let you know if we decide to move forward). If the number of services is small:
select s1.member_id from services s1, services s2, services s3
where s1.member_id = s2.member_id and s2.member_id = s3.member_id
and s1.service_id = 1 and s2.service_id = 2 and s3.service_id = 3
If the number of services is unreasonably high, but member_id,service_id is unique
select member_id from services group by member_id having count(*) = 100;
(if there are 100 services). Worse case scenario (no uniqueness guarantee):
select member_id from services group by member_id having count(distinct service_id) = 100;
Which is slow, but works.