select one column from one table and other columns from another table - mysql

I have the tables :
1. Users : user_id, user_name
2. Transaction : user_id, transaction_number, transaction_date
I want to get the user_id, transaction_number, transaction_date for a particular transaction_date. The first table may contain repeated user_id for different dates and may not contain all user_id for a particular date. The result must contain all user_ids and its transaction_number and transaction dates are null if the user_id has no any transaction entries in the transaction table.
For an example :
user_id transaction_number transaction_date
1 10 12/04/2013
2 0 12/04/2013
3 0 12/04/2013
It shows there are only 3 users and only user_id 1 have transaction in 12/04/2013.

You can replace transaction_number with 0 if it is null depending on the type of database you are using.
Select u.User_id, transactions.transaction_number, '12/04/2013' as transaction_date
from Users u
left join ( Select user_id, Sum(transaction_number)
from Transaction
where transaction_date = '12/04/2013'
Group By user_id
) transactions
on transactions.User_id = u.user_id

select * from Transaction right outer join Users on Transaction.user_id = Users.user_id and Transaction.transaction_date = 'Apr 12 2013 12:00AM'

List all users with transactions if any.Use left join.
select users.user_id,users.user_name,transaction.transaction_number, transaction.date from users left join transaction on users.user_id = transaction.user_id

Related

SQL : Left join with grouped joined rows

I have two tables:
users containing all my users with common attributes
metas holding all dynamic attributes in a one to many relation, (Fyi I cant merge theses attributes into the users table because they can be created / deleted on the fly).
users
id
name
email
1
John
j#d.com
2
Jane
a#d.com
metas
user_id
name
value
1
created_at
"2021-01-01"
1
logged_at
"2021-01-01"
2
created_at
"2021-01-01"
Problem
I want to build a SQL query resulting with something like below, so I can have some where and orders on user metadatas.
id
name
email
created_at
logged_at
1
John
j#d.com
2021-01-01
2021-01-01
2
Jane
a#d.com
2021-01-01
NULL
Progression
I managed to build a result but with only one meta (the created_at) but not logged_at, because I can't group many meta rows for the same user.
SELECT users.*, CAST(JSON_UNQUOTE(value) AS DATE) as created_at
FROM users
LEFT JOIN metas on users.id = metas.user_id and metas.name = 'created_at'
ORDER BY created_at desc
Constraints
It should be done in a single query and can't be done from the code side.
Any suggestions ?
You can join the same table twice.
SELECT users.*,
CAST(JSON_UNQUOTE(m1.value) AS DATE) as created_at,
CAST(JSON_UNQUOTE(m2.value) AS DATE) as logged_at
FROM users
LEFT JOIN metas m1 on users.id = m1.user_id and m1.name = 'created_at'
LEFT JOIN metas m2 on users.id = m2.user_id and m2.name = 'logged_at'
ORDER BY created_at desc
Using a pivot
select *
from
(
select u.id,u.name as user_name,u.email,m.name as meta_name,m.value
from #tUsers as u
left join #tMetas as m on u.id=m.user_id
) as q
pivot
(
max(q.value) for q.meta_name in ([Created_At],[Logged_At])
) as pvt
order by pvt.id

Avoid using a subquery in a table join

In a MySQL 5.7 database, I have the following User table:
Name
Id
David
1
Frank
2
And the following Order table:
Id
Price
UserId
1
55
1
2
68
1
3
50
1
4
10
2
For every user, I want to select the price of the order with the biggest ID.
I can use the following query which adds additional complexity due to the nested subquery :
SELECT
User.Name,
last_user_order.Price
FROM User
LEFT JOIN (
SELECT Price, UserId FROM Order
ORDER BY Id DESC LIMIT 1
) AS last_user_order ON last_user_order.UserId = User.Id
There exist many questions here where the column to be selected is the same than the one being ordered. Hence, it is possible to use MAX in the first SELECT statement to avoid a subquery. Is it possible to avoid a subquery in my case?
For every user, I want to select the price of the order with the biggest ID.
That looks like:
SELECT
u.*,
o.Price,
FROM
User u
INNER JOIN Order o ON u.ID = o.UserID
INNER JOIN
(
SELECT MAX(ID) as OrderID FROM Order GROUP BY UserId
) maxO ON o.Id = maxO.OrderId
SELECT User.Name,
( SELECT Order.Price
FROM Order
WHERE Order.UserId = User.Id
ORDER BY Order.Id DESC LIMIT 1 ) LastPrice
FROM User;

List rows that have an ID in common in the same table with MySQL

I'm building an activities website and I want to show on user's profiles the common activities I'm going to with this other user.
So I have a table as follow :
Every time a user clicks "join" on an activity page, a new row is added to this table with :
the user_id who joined
the activity_id (event) attended
So on each user's profile, I want to list the different activities we have in common.
If the user's IDs are for example 1 and 10, then I can list the activities they go to with this query :
SELECT * FROM `activity_user` WHERE user_id IN(1, 10)
However, how to update this query to return only activities IDs they have in common?
It's a simple JOIN with the same table:
SELECT a1.activity_id
FROM activity_user a1
JOIN activity_user a2 ON a2.activity_id = a1.activity_id
WHERE a1.user_id = 1
AND a2.user_id = 10
Another way is to GROUP BY activity_id and only return activities, which both users have, by counting the rows per group:
SELECT activity_id
FROM activity_user
WHERE user_id IN(1, 10)
GROUP BY activity_id
HAVING COUNT(*) = 2
If the number of user is only limited to 2, this is quite simple using intersect clause -
SELECT activity_id
FROM `activity_user`
WHERE user_id = 1
INTERSECT
SELECT activity_id
FROM `activity_user`
WHERE user_id = 10
For two users you can join two SELECT against same table on activity_id
SELECT a.activity_id
FROM test a
JOIN (SELECT activity_idFROM test WHERE user_id = 10) b ON a.activity_id = b.activity_id
WHERE a.user_id = 1

How to get different results from one mysql table?

I have a user table in the database where all users of the system are stored.
The table has a user_id and a business_name and a first_name.
Some users are merchants and get a business name,
some users are consumers and get a first name.
In a second table I have transactions with a user_id and a merchant_id (which are defining the transaction) and an amount. Both ids reference to user table.
Table users:
user_id bus_name first_name role_id
1 Thomas 10
2 comp1 7
3 Peter 10
4 comp2 7
(role_id is defining with 10=consumer, 7=merchant)
Table transactions:
trans_id amount user_id merchant_id
1 12 1 2
2 23 3 2
3 34 3 4
4 19 1 4
Now I want to have a query with a result as one table:
This table should contain the transaction with amount, user_id, first_name, merchant_id and bus_name.
I want to get this result:
trans_id amount user_id first_name merchant_id bus_name
1 12 1 Thomas 2 comp1
2 23 3 Peter 2 comp1
3 34 3 Peter 4 comp2
4 19 1 Thomas 4 comp2
I have the problem that either I get only the first_name and empty bus_name or I get only the bus_name but empty first_name.
I am using a left join:
...
left join `users`
on(
(`transactions`.`user_id` = `users`.`user_id`)
)
...
But for this I would get for user_id=1 the first_name=Thomas and the bus_name='' would be empty because I only reference to one line in table and not also to different user with user_id=2.
But I want to say something like:
for trans_id=1
get first_name FROM users WHERE transactions.user_id = users.user_id
AND
get bus_name FROM users WHERE transactions.merchant_id = users.user_id
Thanks for your help, I tried so many things but it does not work.
You have to join the user table twice:
SELECT t.*, u.first_name, m.bus_name
FROM transactions t
JOIN users as u
ON t.user_id = u.user_id
JOIN users as m
ON t.merchant_id = m.merchant_id
you could use a duoble join in users table
select a.trans_id, a.amount , a.user_id, b.first_name, a.merchant_id, c. bus_name
from transactions a
inner join users b on a.user_id = b.user_id and b.role_id = 10
inner join users c on a.merchant_id = c.user_id and c.role_id = 7
To join the user table twice worked fine. With "left join users as consumer" I create a kind of a virtual users table called "consumer", this one is joined. Of course in select I had to adjust table name as well. Same for second "virtual" table od users, called "merchant".
select
`transactions`.`trans_id` AS `trans_id`,
`transactions`.`merchant_id` AS `merchant_id`,
`merchant`.`bus_name` AS `bus_name`,
`transactions`.`user_id` AS `user_id`,
`consumer`.`first_name` AS `first_name`,
`cards`.`card_id` AS `card_id`,
`cards`.`serial_no` AS `serial_no`
from (
`transactions`
left join `cards`
on(
(`cards`.`card_id` = `transactions`.`card_id`)
)
left join `users` as consumer
on(
(`consumer`.`user_id` = `transactions`.`user_id`)
)
left join `users` as merchant
on(
(`merchant`.`user_id` = `transactions`.`merchant_id`)
)
)

MYSQL: How to join two tables using Inner join and then calculatin the total number from the second table for the following examples

I am stuck with the following requirement and I am finding it difficult to crack the query for it.
Consider a table customer with the following fields
id signup_date first_payment_date
10 2015-03-20 null
11 2015-03-20 null
12 2015-03-20 null
13 2015-03-20 null
14 2015-05-23 null
15 2015-05-23 null
Consider another table transaction_history
id product_name
10 vod trial
10 vod trial
11 vod trial
12 vod trial
12 vod
13 vod trial
14 vod trial
15 vod trial
15 vod trial
I need to pick the idfrom customer table and look up in transaction_history table based on the signup_date and first_payment_date is null.
Now I need to check if this id is present in transaction_history and check if he has at least 1 entry with product_name = "vod trial". If he has then he is a row in the result I want.
At the end I need to calculate the total number of id's from transaction_history who has at least one row where product_name="vod_trial" and this should be on a date basis mentioned in signup_date in customer table.
I wrote a query in the following manner:
SELECT
ts.guid,
cs.signup_date,
(SELECT
COUNT(ts2.guid)
FROM
transaction_history ts2
WHERE
cs.guid = ts2.guid
AND ts2.product_name = "vod trial"
HAVING COUNT(ts2.guid) = 1) AS count_ts_guid
FROM
customer AS cs,
transaction_history AS ts
WHERE
cs.guid = ts.guid
AND cs.first_payment_date IS NULL;
But in the above query I am not able to calculate the total count signup_datewise.
Would be great if someone could help me out.
Sample result:
date new trials
2015-03-20 2
2015-05-23 1
I am not sure I fully understand. You want customers without first_payment_date that have a trial entry in the transaction table?
select *
from customer
where first_payment_date is null
and id in (select id from transaction_history where product_name = 'vod trial');
Okay, from your last comment it seems, you want customers that have no trial entry in the transaction table, too. And you want to display them with their trial transaction count. So:
select signup_date,
(
select count(*)
from transaction_history th
where th.product_name = 'vod trial'
and th.id = c.id
)
from customer c
where first_payment_date is null;
If you even want to group by date, then aggregate:
select signup_date,
sum((
select count(*)
from transaction_history th
where th.product_name = 'vod trial'
and th.id = c.id
))
from customer c
where first_payment_date is null
group by signup_date;
Next try: Join all customers and transactions, such as to only get customers present in the transactions table. Then aggregate.
select c.signup_date, count(*)
from customer c
join transaction_history th on th.id = c.id and th.product_name = 'vod trial'
where c.first_payment_date is null
group by c.signup_date;
Or do you want this:
select c.signup_date, count(case when th.product_name = 'vod trial' then 1 end)
from customer c
join transaction_history th on th.id = c.id
where c.first_payment_date is null
group by c.signup_date;
I'd better make this a separate answer. You want to find customers that have only one entry in transaction_history and that entry must be 'vod trial'. So read the transaction table, group by customer id and count. Check your criteria with HAVING. Then join the found IDs with the customer table and group by date.
select c.signup_date, count(*)
from customer c
join
(
select id
from transaction_history
group by id
having count(*) = 1
and min(product_name) = 'vod trial'
) t on t.id = c.id
group by c.signup_date;