Getting sum() on a different distinct row MySQL - sql

I was looking on different questions on this issue, but couldn't find an answer for my problem.
This is my query:
SELECT SUM( lead_value ) AS lead_value_sum, count( DISTINCT phone ) AS SUM, referer
FROM leads t1
INNER JOIN leads_people_details t2 ON t1.lead_id = t2.lead_id
INNER JOIN user_to_leads t3 ON t1.lead_id = t3.lead_id
WHERE lead_date
BETWEEN 20100716000000
AND 20100716235959
AND t1.site_id =8
GROUP BY t1.referer
I am trying to sum up the lead_value only of unique phone numbers. The count (Distinct phone) actually works and gives me the number of unique phones for each referer, but I can't seem to understand how should I SUM the lead_value for unique phone numbers at each referer.
Would appreciate any help you can give me,
Eden
Edit: Table Structures
CREATE TABLE user_to_leads
(
user_idINT(10) NOT NULL,
lead_idINT(10) NOT NULL,
site_idINT(10) NOT NULL,
lead_value INT(10) NOT NULL
)
CREATE TABLE leads
(
lead_id INT(100) NOT NULL auto_increment ,
site_id INT(10) NOT NULL ,
lead_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
vaild_date TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
referer VARCHAR(255) NOT NULL,
KEYWORD VARCHAR(255) NOT NULL,
upsaleINT(11) NOT NULL DEFAULT '0' ,
vaild INT(2) NOT NULL,
PRIMARY KEY (lead_id),
KEY lead_date (lead_date)
)
CREATE TABLE leads_people_details
(
lead_id INT(100) NOT NULL auto_increment ,
fullnameVARCHAR(255) NOT NULL,
phone VARCHAR(12) NOT NULL ,
email VARCHAR(255) NOT NULL,
homeVARCHAR(255) NOT NULL,
browser VARCHAR(255) NOT NULL,
browser_version VARCHAR(100) NOT NULL,
resolutionVARCHAR(255) NOT NULL,
IPVARCHAR(255) NOT NULL,
statusVARCHAR(255) NOT NULL DEFAULT '0',
COMMENT text NOT NULL,
PRIMARY KEY (lead_id)
)

You say
For a particular referer,phone, the
lead_value will always be the same
Based on the limited information you have given I think this should return the right answer. If you update your question with the requested information it will probably be possible to improve upon it though.
SELECT SUM(lead_value ) AS lead_value_sum, count(phone ) AS phone_count, referer
FROM
(
SELECT DISTINCT lead_value, phone, referer
FROM leads t1
INNER JOIN leads_people_details t2 ON t1.lead_id = t2.lead_id
INNER JOIN user_to_leads t3 ON t1.lead_id = t3.lead_id
WHERE lead_date
BETWEEN 20100716000000
AND 20100716235959
AND t1.site_id =8
) derived
GROUP BY referer
Upated after table structure posted
I don't really understand why have both leads_people_details and leads got a primary key and auto_increment column of lead_id that you are joining on? That would imply a 1-1 relationship between leads and leads_people_details? If so one of them probably shouldn't be an auto_increment to avoid the possibility of the ids getting out of synch without you realising.
Also there is no Primary Key on the user_to_leads table. Should there one on user_id, lead_id, site_id? Additionally you are not currently filtering by siteid on that table. Is that intentional? If not if you do that does that stop the duplicate records from coming back? If it doesn't then can you describe the significance of user_id in that table? You earlier said that For a particular referer,phone, the lead_value will always be the same can it differ by user_id? If so which should be used? If not why is user_id in that table?
A provisional query that might be closer is here but there are still the unresolved queries above.
SELECT SUM(lead_value ) AS lead_value_sum, count(phone ) AS phone_count, referer
FROM leads t1
INNER JOIN leads_people_details t2 ON t1.lead_id = t2.lead_id
INNER JOIN user_to_leads t3 ON t1.lead_id = t3.lead_id
and t1.site_id = t3.site_id
WHERE lead_date
BETWEEN 20100716000000
AND 20100716235959
AND t1.site_id =8

Related

SQLite: Get Output From Two Tables Using Common Reference ID

I am new in SQLite and i have been working on an issue for quite a long time.
Lets say we have 2 database table say tbl_expense and tbl_category. Please find below the following table structure.
tbl_category
CREATE TABLE IF NOT EXISTS tbl_category(
category_id INTEGER PRIMARY KEY AUTOINCREMENT,
category_name VARCHAR(20) DEFAULT NULL,
category_desc VARCHAR(500) DEFAULT NULL,
category_icon VARCHAR(100) DEFAULT NULL,
category_created timestamp default CURRENT_TIMESTAMP
)
tbl_expense
CREATE TABLE IF NOT EXISTS tbl_expense(
expense_id INTEGER PRIMARY KEY AUTOINCREMENT,
expense_name VARCHAR(20) DEFAULT NULL,
expense_desc VARCHAR(500) DEFAULT NULL,
expense_type VARCHAR(20) DEFAULT NULL,
expense_amt DECIMAL(6.3) DEFAULT NULL,
expense_date TIMESTAMP DEFAULT NULL,
expense_category INTEGER DEFAULT NULL,
expense_created_date timestamp DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (expense_category) REFERENCES tbl_category(category_id)
ON DELETE SET NULL
)
Assume we have data in the tables like this below.
Expected Output:
Assure we have category_id and expense_category as common fields. How can i create an SQL Query where i can list all categories and sum of their expense amount as follows.
Please help me on this issue.
You need an INNER join of the tables and aggregation:
SELECT c.category_name Category,
SUM(e.expense_amt) Amount
FROM tbl_category c INNER JOIN tbl_expense e
ON e.expense_category = c.category_id
GROUP BY c.category_id;
If you want all categories from the table tbl_category, even those that are not present in tbl_expense, use a LEFT join and TOTAL() aggregate function:
SELECT c.category_name Category,
TOTAL(e.expense_amt) Amount
FROM tbl_category c LEFT JOIN tbl_expense e
ON e.expense_category = c.category_id
GROUP BY c.category_id;

PostgreSQL query for Library Management System

Get the member ID and name of the members to whom no more books can be issued, because they have already got as many books issued as the number for which they are entitled
Following are the schemas:
Book_Records(accession_no,isbn_no)
Book(isbn_no, author, publisher, price)
Members(member_id, member_name,max_no_books,max_no_days)
Book_Issue(member_id,accession_no,issue_date,return_date)
CREATE TABLE BOOK (ISBN_NO VARCHAR(35) PRIMARY KEY,
AUTHOR VARCHAR(35) NOT NULL,
PUBLISHER VARCHAR(35) NOT NULL,
PRICE NUMERIC(10,3));
CREATE TABLE BOOK_RECORDS(ACCESSION_NO VARCHAR(35) PRIMARY KEY,
ISBN_NO VARCHAR(35) REFERENCES BOOK(ISBN_NO));
CREATE TABLE MEMBERS(MEMBER_ID VARCHAR(35) PRIMARY KEY,
MEMBER_NAME VARCHAR(35) NOT NULL,
MAX_NO_BOOKS INT,
MAX_NO_DAYS INT);
CREATE TABLE BOOK_ISSUE(MEMBER_ID VARCHAR(35) REFERENCES MEMBERS(MEMBER_ID),
ACCESSION_NO VARCHAR(35) REFERENCES
BOOK_RECORDS(ACCESSION_NO),
ISSUE_DATE DATE NOT NULL,
RETURN_DATE DATE,
PRIMARY KEY(MEMBER_ID,ACCESSION_NO));
I tried the following query but fails.
SELECT DISTINCT member_name
FROM members AS m
JOIN (
SELECT member_id, COUNT(*) AS no_books_issued
FROM book_issue
GROUP BY member_id,accesion_no
HAVING no_books_issued >= max_no_books
) AS b ON m.member_id = b.member_id;
Presumably, a query like this gets the number of books currently issued:
SELECT member_id, COUNT(*) AS num_books
FROM book_issue
WHERE return_date IS NULL
GROUP BY member_id;
My understanding of the maximum number of books would be concurrently -- that is, only count books that have not been returned. Perhaps you have a different definition.
Then, you can use this in a JOIN, doing the comparison on the maximum outside the subquery:
SELECT member_name
FROM members m JOIN
(SELECT member_id, COUNT(*) AS num_books
FROM book_issue
WHERE return_date IS NULL
GROUP BY member_id
) b
ON b.member_id = m.member_id AND
b.num_books >= m.max_no_books;
Notes:
In a JOIN, the comparison to the outer table needs to be outside the subqueries.
No SELECT DISTINCT is needed.
The GROUP BY for counting books should be only at the member level.

Can I SQL join a table twice?

I have two entities: Proposal and Vote.
Proposal: A user can make a proposition.
Vote: A user can vote for a proposition.
CREATE TABLE `proposal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
);
CREATE TABLE `vote` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`idea_id` int(11) NOT NULL,
`updated` datetime NOT NULL,
PRIMARY KEY (`id`),
);
Now I want to fetch rising Propsals, which means:
Proposal title
Total number of all time votes
has received votes within the last 3 days
I am trying to fetch without a subSELECT because I am using doctrine which doesn't allow subSELECTs. So my approach is to fetch by joining the votes table twice (first for fetching the total amount of votes, second to be able to create a WHERE clause to filter last 3 days) and do a INNER JOIN:
SELECT
p.title,
COUNT(v.p_id) AS votes,
DATEDIFF(NOW(), DATE(x.updated))
FROM proposal p
JOIN vote v ON p.id = v.p_id
INNER JOIN vote x ON p.id = x.p_id
WHERE DATEDIFF(NOW(), DATE(x.updated)) < 3
GROUP BY p.id
ORDER BY votes DESC;
It's clear that this will return a wrong votes amount as it triples the votes' COUNT(). It's actually , because it creates a cartesian product just as a CROSS JOIN does.
Is there any way I can get the proper amount without using a subSELECT?
Instead, you can create a kind of COUNTIF function using this pattern:
- COUNT(CASE WHEN <condition> THEN <field> ELSE NULL END)
For example...
SELECT
p.title,
COUNT(v.p_id) AS votes,
COUNT(CASE WHEN v.updated >= DATEADD(DAY, -3, CURRENT_DATE()) THEN v.p_id ELSE NULL END) AS new_votes
FROM
proposal p
JOIN
vote v
ON p.id = v.p_id
GROUP BY
p.title
ORDER BY
COUNT(v.p_id) DESC
;

Two problems with my query: Show null values and order by before group by

I'm having major problems with my query. I want to show all results in the source table even if there is no pricing entry in the right table.
My order by is also not working. I want to order by product_pricing.PP_CashPrice prior to grouping by.
Here is my SQL code:
SELECT * FROM source
LEFT JOIN product_pricing ON source.Source_ID = product_pricing.Source_ID
WHERE (product_pricing.Product_ID = '234'
OR product_pricing.PP_ID = NULL)
AND source.Source_Active = 'Yes'
GROUP by source.Source_ID
ORDER by PP_CashPrice desc
I basically need it to show all sources. The right column will have duplicates but I only need to show the highest one.
My right column is as follows:
CREATE TABLE product_pricing ( PP_ID int(10) NOT NULL AUTO_INCREMENT, PP_Type varchar(150) NOT NULL, PP_CashPrice decimal(10,2) NOT NULL, PP_DateObtained date NOT NULL, PP_TimeObtained time NOT NULL, PP_Active varchar(3) NOT NULL, PP_Postcode varchar(150) NOT NULL, Source_ID int(10) NOT NULL, SC_ID int(10) NOT NULL, Product_ID int(10) NOT NULL, PRIMARY KEY (PP_ID) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
You should not use a where clause on a "Left joined" table. Put the condition in the where clause
I would also use a COALESCE operator for the ordering clause, and probably add an ordering on s.Source_ID if you want different sourceId with "inner pricing" ordering.
SELECT * FROM source s
LEFT JOIN product_pricing pp ON s.Source_ID = pp.Source_ID AND pp.PP_ID = '234'
AND s.Source_Active = 'Yes'
GROUP by s.Source_ID
ORDER by s.Source_ID, COALESCE(p.PP_CashPrice, 0) desc

Problem selecting the latest record in JOIN

These are my 2 tables:
CREATE TABLE `documents` (
`Document_ID` int(10) NOT NULL auto_increment,
`Document_FolderID` int(10) NOT NULL,
`Document_Name` varchar(150) NOT NULL,
PRIMARY KEY (`Document_ID`),
KEY `Document_FolderID` (`Document_FolderID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=331 ;
CREATE TABLE `files` (
`File_ID` int(10) NOT NULL auto_increment,
`File_DocumentID` int(10) NOT NULL,
`File_Name` varchar(255) NOT NULL,
PRIMARY KEY (`File_ID`),
KEY `File_DocumentID` (`File_DocumentID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=333 ;
There can be multiple files to 1 document. I am trying to SELECT all of the documents with a JOIN on the files table but I only want 1 file record which is the latest one.
Here is my query I have come up with that doesn't quite work, can anyone suggest the right way?
SELECT `documents`.*
FROM `documents`
INNER JOIN (
SELECT MAX(`File_ID`), *
FROM `files`
WHERE `File_DocumentID` = `documents`.`Document_ID`
GROUP BY `File_ID` ) AS `file1`
ON `documents`.`Document_ID` = `file1`.`File_DocumentID`
WHERE `documents`.`Document_FolderID` = 94
ORDER BY `documents`.`Document_Name`
*edit: the error is Unknown column 'documents.Document_ID' in 'where clause'
Use:
SELECT d.*, f.*
FROM DOCUMENTS d
JOIN FILES f ON f.file_document_id = d.document_id
JOIN (SELECT t.file_document_id,
MAX(t.file_id) AS max_file_id
FROM FILES t
GROUP BY t.file_document_id) x ON x.file_document_id = f.file_document_id
AND x.max_file_id = f.file_id
The derived table/inline view called "x" is a join to the same table, all it does is tweak the records coming from the FILES table to be the highest per file_document_id...
Don't group by file_id, but by File_documentid.
I think I see what's wrong... You have GROUP BY File_ID, but I guess you really want GROUP BY File_DocumentID instead.