SQL query help - Join on second table, possible? - sql

Two questions.
One: How would I be able to join two tables together, which are not the original FROM 'x' table?
Example: Grabbing all the reports and that users level name.
Report
id | user_id
1 1
User
id | level_id
1 1
Level
id | level_name
1 Admin
SELECT report.id,
report.user_id,
level.name
FROM report
INNER JOIN user
ON report.user_id=user.id
INNER JOIN level
ON user.level_id=level.id
Doesn't seem to work.
Two: How to join tables not from a 1-1 but a 1-many?
Say I wanted to:
SELECT * FROM user JOIN report ON user.id=report.user_id WHERE user.id='4'
But only join with the most recent report ordered by date desc?
I know it seems like I am asking you to do my work for me, but I just need to know what to use to accomplish this, not necessarily you coding it. Thanks.
UPDATE:
First question: Fixed, thanks
Second question:
I'll show you my query to make better sense, I didn't explain it well. I meant a many-many relationship where I grab a list of users and their latest report!
SELECT
user.id
FROM
user
<< INNER JOINS ON OTHER TABLES >>
INNER JOIN
(
SELECT
report.id
FROM
report
WHERE user.id=report.user_id
ORDER BY
date
DESC
LIMIT 1
)

For your second question:
MySQL-style:
SELECT *
FROM user
INNER JOIN report re
ON re.id = (SELECT id
FROM report
WHERE user_id=user.id
ORDER BY report.date DESC
LIMIT 1)
WHERE user.id='4'

One: Looks good to me, but shouldn't that be level.level_name in the SELECT clause?
Two: If you just want the most recent report it would be something like...
SELECT TOP 1 * FROM user JOIN report ON user.id=report.user_id WHERE user.id='4' order by report.date desc

Related

How to query top record group conditional on the counts and strings in a second table

I call on the SQL Gods of the internet!! O so desperately need your help with this query, my livelyhood depends on it. I've solved it in Alteryx in like 2 minutes but i need to write this query in SQL and I am relatively new to the language in terms of complex blending and syntax.
Your help would be so appreciated!! :) xoxox I cant begin to describe
Using SSMS I need to use 2 tables 'searches' and 'events' to query...
the TOP 2 [user]s with the highest count of unique search ids in Table 'searches'
Condition that the [user]s in the list have at least 1 eventid in 'events' where [event type] starts with "great"
Here is an example of what needs to happen
search event and end result example
So the only pieces i have so far are below but boy oh boy please don't Laugh :(
What i was trying to do is..
select a table of unique users with the searchcounts from the search table
inner join selected table from 1 on userid with a table described in 3
create table of unique user ids with counts of events with [type] starting with "great"
Filter the inner joined table for the top 2 search counts from step 1
SELECT userid, COUNT() as searchcount
FROM searches
GROUP BY userid
INNER JOIN (SELECT userid, COUNT() as eventcount
FROM events WHERE LEFT(type, 5) = "great" AND eventcount>0 Group by userid)
ON searches.userid=events.userId
Obviously, this doesn't work at all!!! I think my structure is off and my method of filtering for "great" is errored. Also i dont know how to add the "top 2" clause to the search table query without affecting the inner join. This code needs to be fairly efficient so if you have a better more computationally efficient idea...I love you long time
SELECT top(2) userid, COUNT() as searchcount FROM searches
where userid in (select userid from events where left(type, 5)='great')
GROUP BY userid
order by count() desc
hope above query will serve your purpose.
I think you need exists and windows function dense_rank as follows:
Select * from
(Select u.userid, dense_rank() over (partition by u.userid order by count(*) desc) as rn
From users u join searches s on u.userid = s.userid
Where exists
(select 1 from events e
Where e.userid = u.userid And LEFT(e.type, 5) = 'great')
Group by u.userid ) t Where rn <= 2

Bigquery SQL code to pull earliest contact

I have a copy of our salesforce data in bigquery, I'm trying to join the contact table together with the account table.
I want to return every account in the dataset but I only want the contact that was created first for each account.
I've gone around and around in circles today googling and trying to cobble a query together but all roads either lead to no accounts, a single account or loads of contacts per account (ignoring the earliest requirement).
Here's the latest query. that produces no results. I think I'm nearly there but still struggling. any help would be most appreciated.
SELECT distinct
c.accountid as Acct_id
,a.id as a_Acct_ID
,c.id as Cont_ID
,a.id AS a_CONT_ID
,c.email
,c.createddate
FROM `sfdcaccounttable` a
INNER JOIN `sfdccontacttable` c
ON c.accountid = a.id
INNER JOIN
(SELECT a2.id, c2.accountid, c2.createddate AS MINCREATEDDATE
FROM `sfdccontacttable` c2
INNER JOIN `sfdcaccounttable` a2 ON a2.id = c2.accountid
GROUP BY 1,2,3
ORDER BY c2.createddate asc LIMIT 1) c3
ON c.id = c3.id
ORDER BY a.id asc
LIMIT 10
The solution shared above is very BigQuery specific: it does have some quirks you need to work around like the memory error you got.
I once answered a similar question here that is more portable and easier to maintain.
Essentially you need to create a smaller table(even better to make it a view) with the ID and it's first transaction. It's similar to what you shared by slightly different as you need to group ONLY in the topmost query.
It looks something like this
select
# contact ids that are first time contacts
b.id as cont_id,
b.accountid
from `sfdccontacttable` as b inner join
( select accountid,
min(createddate) as first_tx_time
FROM `sfdccontacttable`
group by 1) as a on (a.accountid = b.accountid and b.createddate = a.first_tx_time)
group by 1, 2
You need to do it this way because otherwise you can end up with multiple IDs per account (if there are any other dimensions associated with it). This way also it is kinda future proof as you can have multiple dimensions added to the underlying tables without affecting the result and also you can use a where clause in the inner query to define a "valid" contact and so on. You can then save that as a view and simply reference it in any subquery or join operation
Setup a view/subquery for client_first or client_last
as:
SELECT * except(_rank) from (
select rank() over (partition by accountid order by createddate ASC) as _rank,
*
FROM `prj.dataset.sfdccontacttable`
) where _rank=1
basically it uses a Window function to number the rows, and return the first row, using ASC that's first client, using DESC that's last client entry.
You can do that same for accounts as well, then you can join two simple, as exactly 1 record will be for each entity.
UPDATE
You could also try using ARRAY_AGG which has less memory footprint.
#standardSQL
SELECT e.* FROM (
SELECT ARRAY_AGG(
t ORDER BY t.createddate ASC LIMIT 1
)[OFFSET(0)] e
FROM `dataset.sfdccontacttable` t
GROUP BY t.accountid
)

SQL How can I create an inner join from these 2 tables

I am just learning sql and I am creating a social network as a learning experience . I have 2 tables called Streams and Votes, Streams pulls user created content and Votes stores the content that people have liked . What I am trying to figure out is how can I return the data from both tables to check if a user a liked a particular post being shown . For instance this is how both my tables look . If you see they both have a field in common stream_id and they both have number 278. How can I do an inner join that checks to see if there are any common stream_ID in both tables ? This is the sql code that I use that gets me the Stream data
Query 1
select post,profile_id,
votes,id as stream_id FROM streams WHERE latitudes>=28.1036 AND
28.9732>=latitudes AND longitudes>=-81.8696 AND -80.8798>=longitudes
order by id desc limit 10
The User ID is 11 and both Streams.profile_id and Votes.my_id are the same field . I have tried this SQL query but this only returns in total 1 result . Again I would like to return all results from the Streams table which I do in query 1 and also add another column to the results from the Votes table where Votes.stream_id=Streams.ID because it'll show that the particular user has liked that post. Any hemp would be great
Query 2
select s.post,s.profile_id,
s.votes,s.id as stream_id, v.my_id as ID FROM streams s inner join Votes v on (s.id = v.stream_id) WHERE latitudes>=28.1036 AND
28.9732>=latitudes AND longitudes>=-81.8696 AND -80.8798>=longitudes
order by id desc limit 10
Streams
Votes
You need to use a LEFT OUTER JOIN instead of an INNER JOIN.
SELECT s.post, s.profile_id, s.votes, s.id as stream_id, v.my_id as ID
FROM streams s
LEFT OUTER JOIN Votes v on (s.id = v.stream_id) WHERE latitudes>=28.1036 AND
28.9732>=latitudes AND longitudes>=-81.8696 AND -80.8798>=longitudes
order by id desc limit 10
For more information about joins, look here.
I think that you are looking for a LEFT JOIN
select s.post,s.profile_id,
s.votes,s.id as stream_id, v.my_id as ID FROM streams s LEFT JOIN Votes v on (s.id = v.stream_id) WHERE latitudes>=28.1036 AND
28.9732>=latitudes AND longitudes>=-81.8696 AND -80.8798>=longitudes
order by id desc limit 10

Combine 2 SQL SELECT statements

** Evidently some people think my question is not worthy of their time. I whole heartedly appologise for this. However, rather than down voting why not use that time to do something positive and at least tell me what info you would require to make this not be a cr#p question in your eyes. **
I have a list of staff in table tblMembers and a list of clients in table tblClients.
One person may have several client.
The staff member associated with a client is identified by staffId against the client record.
Each staff member has a category Id for the type of clients they have catId.
I need to find all of the staff for a given client type and then sort them by the number of clients they have. Staff members without any clients should show a result of 0 rather than not showing.
A simplified table structure would be:
tblMembers:
Id | catId
tblClients:
Id | staffId
Any help would be greatly appreciated.
Thanks!
Try this:
SELECT m.Id 'Member Id', ISNULL(c.StaffCount, 0) 'StuffCount'
FROM tblMembers m
LEFT JOIN
(
SELECT staffId, COUNT(staffId) 'StaffCount'
FROM tblClients
GROUP BY staffId
) c ON m.Id = c.staffId
WHERE m.Cat = 'Some Id'
ORDER BY StuffCount
Its fairly simple to do a join/group and count
SELECT
s.id,
s.catid,
COUNT(c.id)
FROM
tblMembers s
LEFT JOIN tblClients c
ON s.id = c.staffid
WHERE
s.catid = #catID
GROUP BY
s.id,
s.catid
ORDER BY
COUNT(c.id) desc
However the one tricky bit is
show a result of 0 rather than not showing.
To do this you need to do a left join to make sure they show even if there are no matching records and you need to make sure to count a field on the table on the Right side of the join. Otherwise you'd get a count of 1
DEMO
Hope I correctly understood your case.
Try something like this:
SELECT T1.ID,
Count(*)
FROM MEMBERS T1
INNER JOIN CLIENTS T2
ON T1.ID = T2.STAFFID
WHERE T1.CATID = 2
GROUP BY T1.ID
UNION
SELECT DISTINCT ID,
0
FROM MEMBERS
WHERE CATID != 2
A working sample is available here.
try:
select tblMembers.id, count(tblClient.id)
from tblMembers left join tblCLient on staffId = tblMembers.id
where tblMembers.catId = ??
group by tblMembers.id
order by 2 desc

Count query results on multi-join statements

select cnt.loginid, grp.last_name as 'Group Name'
from contact cnt
right join grpmem list on cnt.contact_uuid = list.member
left join contact grp on grp.contact_uuid = list.group_id
join contact_acctyp cntacc on cnt.contact_uuid = cntacc.contact_uuid
where cntacc.c_acctyp_id in (select id from acctyp_v2 where sym like 'CDN%')
I have written a query for our system that pulls a list of all Canadian contacts and the group they are in.
Now, for people who are in multiple groups (their loginid appears multiple times) I need to determine the number of groups they are in (return a count). However, I am unsure of how to perform the count.
I'd like my output to be in the following format:
| USER ID | # of Groups |
I can't seem to figure out how to turn what I've written into that.
Assuming all you want to do is aggregate the information you are already getting back, and without looking in detail at your query, here is a guess:
select
cnt.loginid,
COUNT(*)
from contact cnt
right join grpmem list on cnt.contact_uuid = list.member
left join contact grp on grp.contact_uuid = list.group_id
join contact_acctyp cntacc on cnt.contact_uuid = cntacc.contact_uuid
where cntacc.c_acctyp_id in (select id from acctyp_v2 where sym like 'CDN%')
GROUP BY
cnt.loginid