sql not showing proper result - mysql

I have following tables in mySql.
blog
Field Type
---------- ------------
id int(11)
name varchar(255)
user_id int(11)
share int(14)
user_blog_analytics
Field Type
----------- ------------
id int(11)
blog_id int(11)
ip varchar(255)
impressions int(11)
date date
user_profile
Field Type
----------- ------------
id int(11)
user_id int(11)
description text
share int(14)
user_profile_analytics
Field Type
----------- ------------
id int(11)
user_id int(11)
ip varchar(255)
impressions int(11)
date date
users
Field Type
----------- ------------
id int(11)
email varchar(255)
I want a query that gives me total blog shares of each users from blog table, total profile shares of each users from user_profile table, total blog views from yesterday i.e. from user_blog_analytics table, all time views on profile from user_profile_analytics table.
I created a query but not giving me the results I expect, it only gives me few results.
SELECT a.user_id, COUNT(DISTINCT b.ip) AS blog_view_count, a.share AS blog_share_count, c.share AS profile_share_count, COUNT(DISTINCT d.ip) AS user_profile_view
FROM blog AS a
JOIN user_blog_analytics AS b ON b.blog_id=a.id
JOIN user_profile AS c ON c.user_id=a.user_id
JOIN user_profile_analytics AS d ON d.user_id=c.user_id
JOIN users AS e ON e.id=a.user_id
WHERE DATE_SUB(CURDATE(), INTERVAL 1 DAY) = b.date AND e.role_id=2
GROUP BY a.id;
When I ran this query it gives me only one result but when I manually checked the tables then it should be giving me at least 2 results. Tell me where I am wrong and how can I get the result by modifying this query.

Try this:
SELECT u.id, u.email, b.blog_share_count, b.blog_view_count,
up.profile_share_count, upa.user_profile_view
FROM users u
LEFT JOIN (SELECT b.user_id, SUM(b.share) AS blog_share_count, COUNT(DISTINCT b.ip) AS blog_view_count
FROM blog b
LEFT JOIN user_blog_analytics AS uba ON uba.blog_id = b.id AND DATE_SUB(CURDATE(), INTERVAL 1 DAY) = uba.date
GROUP BY b.user_id
) b ON u.id = b.user_id
LEFT JOIN (SELECT up.user_id, SUM(up.share) AS profile_share_count
FROM user_profile up
GROUP BY up.user_id
) up ON u.id = up.user_id
LEFT JOIN (SELECT up.user_id, COUNT(DISTINCT up.ip) AS user_profile_view
FROM user_profile_analytics up
GROUP BY up.user_id
) upa ON u.id = upa.user_id

Not an answer, but something to think about...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table(i14 INT(14),i4 INT(4));
INSERT INTO my_table VALUES (123456789012345,123456789012345);
SELECT * FROM my_table;
+------------+------------+
| i14 | i4 |
+------------+------------+
| 2147483647 | 2147483647 |
+------------+------------+
So, the numbers in parentheses ain't doing much for ya!

Related

Greatest n per group in a many to many relationship

I know there are many questions similar to this one but it seems that nothing fits my problem. I've spent quite a few hours researching this problem and came up with a query that doesn't select the last image, more on that later. So, the problem is a have 3 tables
table: images
| Field | Type
+-------------------+------------------
| id | int(10) unsigned
| filename | varchar(255)
| created_at | timestamp
| updated_at | timestamp
table: offers
| Field | Type
+-------------------+------------------
| id | int(10) unsigned
| message | varchar(255)
| created_at | timestamp
and a table connecting them: offer_images
| Field | Type
+----------+------------------
| offer_id | int(10) unsigned
| image_id | int(10) unsigned
So, the question is:
How do I select all offers with the last updated image (based on updated_at) from the images table that is linked to the offer. Here is what I got so far:
SELECT `o`.*, `i`.`filename`
FROM `offer_images` AS `oi`
INNER JOIN `offers` AS `o` on `oi`.`offer_id` = `o`.`id`
INNER JOIN `images` as `i` on `oi`.`photo_id` = `i`.`id`
GROUP BY `o`.`id`
The query selects everything and it's working besides that it ignores the updated_at field.
Try this:
SELECT o.*, i.*
FROM offers AS o
INNER JOIN (
-- Get the latest update_at date per offer_id
SELECT oi.offer_id, MAX(updated_at) AS max_updated_at
FROM offer_images AS oi
INNER JOIN images AS i ON oi.image_id = i.id
GROUP BY oi.offer_id
) AS d ON o.id = d.offer_id
INNER JOIN offer_images AS oi ON oi.offer_id = d.offer_id
INNER JOIN images AS i ON i.id = oi.image_id AND i.updated_at = d.max_updated_at
The query uses a derived table to get the latest update_at date per offer_id. Using this date we can join back to the images table in order to get the greatest-n-per-group record.

Get data from 3 table

I have three tables in my database first one is account_group, next is ledger and last one is account_receipt,
account_group has fields group_id and group_name, and this group_id is mapped to ledger, ledger table contains fields ledger_name and group_id. and in the last table account_receipt has fields ledger_id and receipt_amount.
so what I need is I want to get receipt details when group_id is given.I cant write the query for this.any help would be appreciated.
schema::
account_group::
id int(11)
group_name varchar(60)
ledger ::
id int(11)
group_id varchar(60)
ledger_name varchar(60)
account_receipt::
id int(11)
ledger_id int(11)
amount float
receipt_date date
Try the following query. It uses JOINs to connect the various tables, column aliases and table aliases.
SELECT
ag.id group_id,
l.id ledger_id,
l.ledger_name ledger_name
ar.id receipt_id,
ar.amount amount,
ar.receipt_date receipt_date
FROM account_receipt ar
INNER JOIN ledger l ON ar.ledger_id = l.id
INNER JOIN account_group ag ON ag.id = l.group_id AND ag.id = <given group id>;
Three table joining example has been given below
select * from Table_A A
join Table_B B on B.id=A.id
join Table_C C on C.id=A.id

SQL statement for join but not in other table

I have two tables: customer and mailing :
+==========+ +=============+
| customer | | mailing |
+==========+ +=============+
| id | | id |
+----------+ +-------------+
| name | | customer_id |
+----------+ +-------------+
| mailing_id |
+-------------+
Every time I send a mailing to a customer, I add a row in the mailings table with that mailing id. One mailing can be sent to multiple customers.
I want to have a sql call that returns all customers that have not yet received a certain mailing. How to ?
I am using mysql
select * from customer where id not in (
select customer_id from mailing where mailing_id = #mailing_id
)
Something like
Select c.ID, c.Name
From Customers C
left Join mailing m On c.id = m.customer_id
where m.customer_id is null
SELECT * FROM customers c
JOIN mailings m
ON c.id = m.id
WHERE NOT EXISTS (
SELECT id
FROM mailings i
WHERE i.id = c.id
GROUP BY i.id
)
What you describe is called an ANTI JOIN. Usually there are three different ways for formulating it in SQL: A NOT IN condition with a subquery, a NOT EXISTS condition with a correlated subquery, or a LEFT JOIN with a NOT NULL condition.
So for your query the possibilities are:
SELECT *
FROM customer
WHERE id NOT IN
( SELECT customer_id
FROM mailing)
SELECT *
FROM customer c
WHERE NOT EXISTS
( SELECT customer_id
FROM mailing m
WHERE m.customer_id = c.id)
SELECT *
FROM customer c
LEFT JOIN mailing m ON c.id = m.customer_id
WHERE m.customer_id IS NULL
This blog post compares the different possibilities with MySQL 5.1. According to it, LEFT JOIN / IS NULL and NOT IN are faster than NOT EXISTS.
However, you should try for yourself which one is the fastest. That always depends on your data, indexes, ...

SQL SELECT QUERY

i have 3 tables:
users:
uid int(11) - userid(primary key, auto_increment)
name varchar(255)
pass varchar(64)
created int(11)
projects:
pid int(11) .....
name varchar(150)
description varchar(255)
created int(11)
users_projects:
uid int(11) - user id
pid int(11) - product id
What is the query for: showing the projects(name and description) sorted by name for the user with a certain name?
This is what i've got so far:
SEECT name,description FROM projects ORDER BY name ASC
SELECT a.*, b.*
FROM users a
INNER JOIN users_projects b
ON a.uid = b.uid
INNER JOIN projects c
ON b.pid = c.pid
ORDER BY a.Name ASC
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Looks like you just need to join up the tables. Here #Name is a parameter containing the user's name you want project details for:
SELECT projects.Name,
projects.Description
FROM projects
INNER JOIN users_projects
ON projects.pid = users_projects.pid
INNER JOIN Users
ON users_projects.UId = Users.UId
WHERE Users.Name = #Name
ORDER BY projects.Name ASC

SQL - selecting last row ordered by a date

This is my SQL:
"SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users INNER JOIN friends ON (users.id_user = friends.id_user)
GROUP BY username ORDER BY username";
This is the output on my webpage:
Username Friend's Name Meeting Date
George Nicolas 2010
Man Anatol 2008
For now, it selects just the first rows from database for each user.
Each table has an auto_increment, id_user for the first table and id_friend for the second one.
I would like it to show that friend which were meet last by each user.
I've tried to add an order by "meet_date DESC" but it doesn't work.
How could I achieve my wish?
One standard trick is to use an outer self join:
SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users
INNER JOIN friends ON (users.id_user = friends.id_user)
LEFT JOIN friends f2 ON friends.meet_date > f2.meet_date
WHERE f2.(primary key) IS NULL
GROUP BY username
ORDER BY username
which finds the date for which there is no other record with a greater date value. This avoids the inefficiencies of correlated subqueries and extra aggregates; or the doubtful assumption that records are always added in meet-date order which is necessary if you want to use the primary key.
* Edited by other user *
You should replace (primary key) by primary key column table or just by a f2 column:
SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users
left JOIN friends ON (users.id_user = friends.id_user)
LEFT JOIN friends f2 ON friends.meet_date > f2.meet_date
WHERE f2.id_user IS NULL
GROUP BY username
ORDER BY username
Query runs as spected:
| USERNAME | ID_USER | NAME | MEET_DATE |
-------------------------------------------
| a | 1 | c | 0 |
| b | 2 | (null) | (null) |
The easy way is a subquery:
SELECT
users.username,
users.id_user,
( select friends.name
from friends
where (users.id_user = friends.id_user)
ORDER BY friends.meet_date desc
LIMIT 1 ) as friend_name,
( select friends.meet_date
from friends
where (users.id_user = friends.id_user)
ORDER BY friends.meet_date desc
LIMIT 1 ) as friend_meet_date
FROM users
;
* Testing *
create table users (username varchar(50), id_user int);
create table friends ( name varchar(50), id_user int, meet_date int);
insert into users values ( 'a', 1),('b',2);
insert into friends values ('c', 1, 0), ('d',1,1);
Results:
| USERNAME | ID_USER | FRIEND_NAME | FRIEND_MEET_DATE |
-------------------------------------------------------
| a | 1 | d | 1 |
| b | 2 | (null) | (null) |
Try it at sql fiddle.
Notice thant a correlated subquery is not an elegant approach, is the easy approach.
Do you not have an auto_increment field? This would allow you to sort by that. The other option is to change meet_date to a date field so you can properly sort by it. No reason to store a DateTime as a varchar field
Assuming that you have got id as a primary key with auto_increment in users table, this should do the trick:
SELECT MAX(users.id), users.username, users.id_user, friends.name, friends.meet_date
FROM users INNER JOIN friends ON (users.id_user = friends.id_user)
GROUP BY username ORDER BY username
SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users INNER JOIN friends ON (users.id_user = friends.id_user)
GROUP BY username ORDER BY username
having max(friends.meet_date)=friends.meet_date