Count of records from multiple tables - sql-server-2008

I have two Tables named SavingAccountTransactions and LoanAccountTransactions.
Both the tables are having same columns (fk_MemberId,fk_AgentId,TransactionDate)
Sample Data
SavingAccountTransactions Table
Id fk_MemberId fk_AgentId TransactionDate Amount
--- ----------- ----------- --------------- -------
1 441 12 2014-12-30 100
2 452 6 2014-12-30 300
LoanAccountTransactions Table
Id fk_MemberId fk_AgentId TransactionDate Amount
--- ----------- ----------- --------------- -------
1 441 12 2014-12-30 500
2 452 6 2014-12-30 200
How can i combine SavingAccountTransactions and LoanAccountTransactions tables to get the count of NoOfMembersVisited in a single row for particular member.
Below is the query which i have tried
select u.Fullname as AgentName ,count (distinct t.fk_MemberId ) as NoOfMembersVisited
from dbo.SavingAccountTransactions T
inner join Users u on t.fk_AgentId=u.Id
where t.TransactionDate = CAST(GETDATE() AS DATE)
group by u.Fullname
Union all
select u.Fullname as AgentName, count (distinct l.fk_MemberId ) as NoOfMembersVisited
from LoanAccountTransactions L
inner join Users u on L.fk_AgentId=u.Id
where l.TransactionDate = CAST(GETDATE() AS DATE)
group by u.Fullname
Expected Result:
AgentName NoOfMembersVisited
--------- -------------------
John 2
Kevin 1
etc....

Because you have not provided any sample data it is hard to know what you are getting. But I might have an idea what you problem is. When you use the UNION ALL the users get repeated if they are in both of the table. Because it might be different counts from the tables changing the UNION ALL to UNION will not work. I would like to suggest you to do something like this:
;WITH CTE
AS
(
select u.Fullname as AgentName,l.fk_MemberId
from dbo.SavingAccountTransactions T
inner join Users u on t.fk_AgentId=u.Id
where t.TransactionDate = CAST(GETDATE() AS DATE)
UNION ALL
select u.Fullname as AgentName,l.fk_MemberId
from LoanAccountTransactions L
inner join Users u on L.fk_AgentId=u.Id
where l.TransactionDate = CAST(GETDATE() AS DATE)
)
SELECT
CTE.Fullname,
COUNT(distinct CTE.fk_MemberId) as NoOfMembersVisited
FROM
CTE
group by
CTE.Fullname

Related

Join tables and sort by 2 different columns

I have query that make a list of payments (payment table) and I would like to have it sorted by the date of the tasks (2 separate tables - quotedb and packaging) these payments are related to
My Query:
SELECT a.*
FROM payments AS a
LEFT JOIN quotedb AS b ON a.orderid = b.id
LEFT JOIN packaging AS p ON a.orderid = p.id
WHERE a.status='Pending' AND (b.moveday<'$today' OR p.datestamp<'$today')
ORDER BY b.moveday, p.datestamp
payments table example:
id payment orderid
-------------------
1 payment1 1
2 payment2 2
3 payment3 3
4 payment4 4
5 payment5 5
6 payment6 6
quotedb table example:
id moveday
-----------
1 05.07.18 > related to payments table id 1
2 08.07.18
3 10.07.18
packaging table example:
id datestamp
-----------
4 06.07.18 > related to payments table id 4
5 07.07.18
6 19.07.18
I join results from the tables, but I have a problem with sorting, query seem to print the "packaging" table results unsorted, and then results from "quotedb" sorted by moveday
I want these results to be sorted by (joined moveday and datestamp)
You can use UNION ALL to combine quotedb and packaging tables. and use grp make a number to make Order by sequence number
SELECT a.*
FROM payments a
LEFT JOIN
(
SELECT 1 grp,id,moveday AS day
FROM quotedb
UNION ALL
SELECT 2,id,datestamp
FROM packaging
) t on a.orderid = t.id
ORDER BY t.grp,t.day
sqlfiddle
SELECT a.*
FROM payments AS a
LEFT JOIN
(
SELECT orderno, moveday AS sortdate FROM quotedb
UNION ALL
SELECT orderno, datestamp AS sortdate FROM packaging
) t on a.orderno = t.orderno
WHERE a.status='Pending' AND sortdate<'$today'
ORDER BY sortdate

MySQL - Display null column from child table if all values are not distinct

I have the following tables, for example:
invoices
ID Name
1 A
2 B
3 C
4 D
5 E
transactions
ID Invoice_ID User_ID
1 1 10
2 1 10
3 1 10
4 2 30
5 3 20
6 3 40
7 2 30
8 2 30
9 4 40
10 3 50
Now I want to make a select that will pull the invoices and the user_id from the related transactions, but of course if I do that I won't get all the ids, since they may be distinct but there will be only one column for that. What I want to do is that if there are distinct User_ids, I will display a pre-defined text in the column instead of the actual result.
select invoices.id, invoices.name, transactions.user_id(if there are distinct user_ids -> return null)
from invoices
left join transactions on invoices.id = transactions.invoice_id
and then this would be the result
ID Name User_ID
1 A 10
2 B 30
3 C null
4 D 40
5 E null
Is this possible?
You can do the following :
select
invoices.id,
invoices.name,
IF (
(SELECT COUNT(DISTINCT user_id) FROM transactions WHERE transactions.invoice_id = invoices.id) = 1,
(SELECT MAX(user_id) FROM transactions WHERE transactions.invoice_id = invoices.id),
null
) AS user_id
from invoices
Or, alternatively, you can use the GROUP_CONCAT function to output a comma-separated list of users for each invoice. It is not exactly what you asked, but maybe in fact it will be more useful :
select
invoices.id,
invoices.name,
GROUP_CONCAT(DISTINCT transactions.user_id SEPARATOR ',') AS user_ids
from invoices
left join transactions on invoices.id = transactions.invoice_id
group by invoices.id
Try somethingh like:
select i.id, i.name, t.user_id
from invoices i left join
(
select invoice_ID, User_ID
from transactions
group by invoice_ID
having count(invoice_ID)=1
) t on i.id=t.invoice_id
SQL fiddle
You could list all the transactions that have multiple user ids, like this:
select invoices.id, invoices.name, null
from invoices
left join transactions on invoices.id = transactions.invoice_id having count(distinct transactions.user_id) > 1
Also, I think this CASE might suit your needs here:
select invoices.id, invoices.name,
case when count(distinct transactions.user_id) > 1 then null else transactions.user_id end
from invoices
left join transactions on invoices.id = transactions.invoice_id
group by invoices.id
although, I'm not sure this is syntactically correct

SQL - How to calculate column value and join with another table

As I am not good with MySQL query's so I wish someone help me for creating this kind of sql query.
I having two MySQL tables which is describe bellow:
Table Name: rating
-------------------
property_id user_id area_rate_count safety_rate_count friendly_rate_count walkability_rate_count
4 28 1 1 1 2
5 38 2 3 4 1
5 40 2 2 3 1
6 40 2 3 1 4
10 43 2 2 3 1
Table Name: listing
-------------------
property_id title
4 Sample 1
5 Sample 2
6 Sample 3
10 Sample 4
11 Sample 5
12 Sample 6
Now first I want to sum each column and divide. (area_rate_count, safety_rate_count, friendly_rate_count, walkability_rate_count). For example In property_id:5 having two times so first calculate column sum and divide by 2.
After calculation we will get this output:
Table Name: rating (After Calculation)
--------------------------------------
property_id rate
4 5
5 9 (Divided by 2 because this property_id is two times in table)
6 10
10 8
And Finally I want join this result to my listing table and result looks something like this:
Table Name: listing
-------------------
property_id title rate
4 Sample 1 5
5 Sample 2 9 (Divided by 2 becouse property_id is two times in table)
6 Sample 3 10
10 Sample 4 8
11 Sample 5 0
12 Sample 6 0
Thanks.
I think you want the avg() aggregation function along with a join:
select l.property_id, l.title,
coalesce(avg(area_rate_count + safety_rate_count + friendly_rate_count + walkability_rate_count
), 0) as rate
from listing l left outer join
property_id p
on l.property_id = p.property_id
group by l.property_id, l.title ;
If I understood it right I think you need this:
select l.property_id, l.title, coalesce(r.ssum/if(r.ct=0,1,r.ct), 0) as rate
from listing l LEFT JOIN
(select property_id,
sum(area_rate_count+safety_rate_count
+friendly_rate_count+walkability_rate_count) ssum,
count(*) ct
from rating
group by property_id ) r
ON l.property_id = r.property_id
order by l.property_id
See it here on fiddle: http://sqlfiddle.com/#!2/589d6/5
Edit
As OP asked on the comments that he wants all columns from listing here is what he want:
select l.*, coalesce(r.ssum/if(r.ct=0,1,r.ct), 0) as rate
from listing l LEFT JOIN
(select property_id,
sum(area_rate_count+safety_rate_count
+friendly_rate_count+walkability_rate_count) ssum,
count(*) ct
from rating
group by property_id ) r
ON l.property_id = r.property_id
order by l.property_id
CREATE TEMPORARY TABLE IF NOT EXISTS
temp_table ( INDEX(col_2) )
ENGINE=MyISAM
AS (
SELECT
property_id,
AVG(area_rate_count) as area_rate_count,
AVG(safety_rate_count) as safety_rate_count,
AVG(friendly_rate_count) as friendly_rate_count,
AVG(walkability_rate_count) as walkability_rate_count
FROM rating
GROUP BY property_id
)
SELECT * FROM listing L
JOIN temp_table T
ON L.property_id = T.property_id
Use the below statement to get distinct property_id with its own rate
select property_id, sum(separaterating)/count(property_id) from (
select property_id,sum(area_rate_count , safety_rate_count , friendly_rate_count , walkability_rate_count) as separaterating from rating group by property_id AS temp ) group by
property_id
you can then join with the other table to get the final result as below
select * from ( select property_id, sum(separaterating)/count(property_id) from (
select property_id,sum(area_rate_count , safety_rate_count , friendly_rate_count , walkability_rate_count) as separaterating from rating group by property_id AS temp ) group by
property_id) AS A inner join listing AS B on A.property_id = B.property_id
try this:
select a.prop_id as property_id, l.title, a.allratings / b.numberofreviews as rate
from
(
select property_id as prop_id, SUM(coalesce(area_rate_count,0) + coalesce(safety_rate_count,0) + coalesce(friendly_rate_count,0) + coalesce(walkability_rate_count,0)) as allratings
from rating
group by property_id
) a inner join
(
select property_id, count(distinct user_id) as numberofreviews
from rating
group by property_id
) b on a.property_id = b.property_id
inner join listing l on a.property_id = l.property_id
Try This Query
select ls.property_id,ls.title,inr.rate from listing as ls
left join
(select r.property_id as pid,r.rate/r.cnt as rate from
(select property_id,user_id,(area_rate_count+safefty_rate_count+friendly_rate_count+walkability_rate_count) as rate,count(*) as cnt from rating group by property_id) as r) as inr on inr.pid=ls.property_id

getting latest timestamp from 2 joined tables for each row output in select statement

I have 3 tables as shown below. I want to get a list of member names, ids, together with the latest activity time for each of them, given a particular member name search term.
This 'latest activity time' is the latest time from comparing both the game_record and the eating_record tables.
The desired output is also given below.
member_info table:
name m_id
---- ----
john 1
doe 2
johnson 3
game_record:
time_of_activity game_id m_id
---------------- ------- -----
2013-01-20 23:01:00 1 3
2013-01-20 23:01:07 4 1
2013-01-20 23:01:06 1 2
2013-01-20 23:01:05 3 1
eating_record:
time_of_activity food_id m_id
---------------- ------- -----
2013-01-20 23:01:04 1 1
2013-01-20 23:01:03 4 1
2013-01-20 23:01:02 1 2
2013-01-20 23:01:01 3 3
desired output when search term is 'john':
name m_id latest_time
---- ---- -----------
john 1 2013-01-20 23:01:07
johnson 3 2013-01-20 23:01:01
What I have tried so far:
I can get the first 2 columns by the following query:
select name,
m_id
from
member_info
where
name like "john%";
And I can get the latest_time for a given member by the following query, but I'm not sure how to merge this second query with the first one to get my desired output.
select greatest ((select
max(time_of_activity)
from
game_record
join
member_info on game_record.m_id = member_info.m_id
where member_info.name = "john"),
(select
max(time_of_activity)
from
eating_record
join
member_info on eating_record.m_id = member_info.m_id
where member_info.name = "john"));
SQL Fiddle for this is available at: http://sqlfiddle.com/#!2/b70d0/3
P.S. The tables game_record and eating_record have other columns that are particular to games/food that are not included here, since I wanted to simplify and isolate the part where I needed help.
Thank you! :)
You could use a UNION ALL query to get the eating_record and game_record times in the same column, then apply an aggregate function to get the max time:
select m.name,
m.m_id,
max(time_of_activity) latest_time
from member_info m
left join
(
select time_of_activity, m_id
from game_record
union all
select time_of_activity, m_id
from eating_record
) g
on m.m_id = g.m_id
where m.name like 'john%'
group by m.name, m.m_id
See SQL Fiddle with Demo.
This could also be written with aggregates in the subquery:
select m.name,
m.m_id,
max(time_of_activity) latest_time
from member_info m
left join
(
select max(time_of_activity) time_of_activity, m_id
from game_record
group by m_id
union all
select max(time_of_activity) time_of_activity, m_id
from eating_record
group by m_id
) g
on m.m_id = g.m_id
where m.name like 'john%'
group by m.name, m.m_id;
See SQL Fiddle with Demo
My solution is to aggregate each of the tables (games and eating) by member id to get the latest time. Then, join these together and use the greatest() function to get the latest time:
select mi.*, greatest(gr.maxtime, er.maxtime) as latest_time
from member_info mi left outer join
(select m_id, MAX(time_of_activity) as maxtime
from game_record gr
group by m_id
) gr
on gr.m_id = mi.m_id left outer join
(select m_id, MAX(time_of_activity) as maxtime
from eating_record er
group by m_id
) er
on er.m_id = mi.m_id

SQL count non sequential dates

Here's the data:
empID Date Type
----- -------- ----
1 1/1/2012 u
1 1/2/2012 u
1 1/3/2012 u
1 2/2/2012 u
4 1/1/2012 u
4 1/3/2012 u
4 1/4/2012 u
4 1/6/2012 u
Would return:
empID count
----- -----
1 2
4 3
When two dates are "together" they count as one occurrence, if the dates are separated out, they count as two occurrences. This is for tracking employee attendance... how would the SQL statement look to group by "together" dates and count them as 1... I'm really struggling with the logic.
SELECT
empID
, COUNT(*) AS cnt
FROM
tableX AS x
WHERE
NOT EXISTS
( SELECT *
FROM tableX AS y
WHERE y.empID = x.empID
AND DATEADD ("d", -1, x.[Date]) = y.[Date]
)
GROUP BY
empID ;
try this:
;WITH CTE as
(select *,ROW_NUMBER() over (partition by empID order by date) as rn from test2 t1)
select empID,COUNT(*) as count
from CTE c1
where isnull((DATEDIFF(day,(select date from CTE where c1.rn=rn+1 and empID=c1.empID ),c1.date)),0) <> 1
group by empID