I am trying to write a query that will login name associated with a block session id if there is a blocking id >0
For instance, when I use the query on this table below:
login_name session_id blocking_session_id
Billy 50 0
Benjamin 60 70
John 70 0
I want the query to output
login_name session_id
John 70
Thanks for your help
You can do this in a single query by joining the same table twice on t1.session_id = t2.blocking_session_id (no need for a SELECT inside a SELECT) and selecting the desired fields from t1:
working example: http://www.sqlfiddle.com/#!9/685824/2
select t1.login_name, t1.session_id
from mytable as t1
join mytable as t2
on t1.session_id = t2.blocking_session_id
As I understand your question, you want the login names that own blocking sessions.
You can use exists for this:
select t.*
from mytable t
where exists (select 1 from mytable t1 where t1.blocking_session_id = t.session_id)
Related
I have a table called 'users' that has the following structure:
id (PK)
campaign_id
createdAt
1
123
2022-07-14T10:30:01.967Z
2
1234
2022-07-14T10:30:01.967Z
3
123
2022-07-14T10:30:01.967Z
4
123
2022-07-14T10:30:01.967Z
At the same time I have a table that tracks clicks per user:
id (PK)
user_id(FK)
createdAt
1
1
2022-07-14T10:30:01.967Z
2
2
2022-07-14T10:30:01.967Z
3
2
2022-07-14T10:30:01.967Z
4
2
2022-07-14T10:30:01.967Z
Both of these table are up to millions of records... I need the most efficient query to group the data per campaign_id.
The result I am looking for would look like this:
campaign_id
total_users
total_clicks
123
3
1
1234
1
3
I unfortunately have no idea how to achieve this while minding performance and most important of it all I need to use WHERE or HAVING to limit the query in a certain time range by createdAt
Note, PostgreSQL is not my forte, nor is SQL. But, I'm learning spending some time on your question. Have a go with INNER JOIN after two seperate SELECT() statements:
SELECT * FROM
(
SELECT campaign_id, COUNT (t1."id(PK)") total_users FROM t1 GROUP BY campaign_id
) tbl1
INNER JOIN
(
SELECT campaign_id, COUNT (t2."user_id(FK)") total_clicks FROM t2 INNER JOIN t1 ON t1."id(PK)" = t2."user_id(FK)" GROUP BY campaign_id
) tbl2
USING(campaign_id)
See an online fiddle. I believe this is now also ready for a WHERE clause in both SELECT statements to filter by "createdAt". I'm pretty sure someone else will come up with something better.
Good luck.
Hope this will help you.
select u.campaign_id,
count(distinct u.id) users_count,
count(c.user_id) clicks_count
from
users u left join clicks c on u.id=c.user_id
group by 1;
See here query output
I have a website sessions table with session id as the key. Each session should only have a single source - where the session came from. However, a small minority appear twice. Of those who appear twice, a smaller minority still have differing sources.
If I have a table of the form:
session_id | source
123456 | apples
abcdef | oranges
654321 | apples
abc123 | pears
def456 | oranges
123456 | pears
Each id should have only a single source. However, id 123456 has both apples and pears as a source. I would like to write a query that returns the ids like 123456, where they have more than one source next to them.
How could I do that?
Aggregate per session and count number of different sources:
select session_id, string_agg(distinct source, ',') as sources
from mytable
group by session_id
having count(distinct source) > 1
order by session_id;
You can take the distinct session_id and source and get the count(*) bigger than 1
select session_id
from (select distinct session_id, source from tbl) a
group by session_id
having count(*) > 1
having clause is good but dramatically slow just because it needs to scan the whole table.
Having appropriate indexes, try to start somewhere like
select *
from
your_table as t1 join your_table as t2 on (t1.session_id = t2.session_id and t1.source <> t2.source);
Thanks to #ThorstenKettner for reminding me about exists, this could be even more efficient:
select * from your_table as t1
wherte
exists (
select 1 from your_table as t2
where t1.session_id = t2.session_id and t1.source <> t2.source)
Each time a user searches for a text on the website, the search text gets recorded to search_table. The sub-searches are also recorded. They are recorded with an asterisk.
The goal is to find the most complete search texts that the user searched for.
The ideal way would be:
Group the ids = 1,4,6 and obtain id=6
Group the ids = 2,5,7 and obtain id = 7
Group the ids = 3 and obtain id = 3
Group the ids 8, 9 and obtain id = 9
SEARCH_TABLE
id user search_text
--------------------
1 user1 data manag*
2 user1 confer*
3 user1 incomplete sear*
4 user1 data managem*
5 user1 conference c*
6 user1 data management
7 user1 conference call
8 user1 status in*
9 user1 status information
Output should be
user search_text
---------------------
user1 data management
user1 conference call
user1 incomplete sear*
user1 status information
Can you help please?
Something like below should do the work:
SELECT * FROM
SEARCH_TABLE st
WHERE
NOT EXISTS (
SELECT 1 FROM
SEARCH_TABLE st2
-- remove asterkis and ad %
WHERE st2.search_Text LIKE replace(st.search_text,'*','')||'%'
)
This is filtering all searches that are part of others.
This is probably not the most elegant way, but here's a go at it:
alter table your_table
add group_id int
select [user], left(search_text, 5) as Group_Text, IDENTITY(int, 1,1) as Group_ID
into #group_id_table
from your_table
group by [user], left(search_text, 5)
order by [user], left(search_text, 5)
update a
set a.group_id = b.group_id
from your_table as a
join #group_id_table as b
on left(search_text, 5) = group_text
select [user], max(search_text), group_id
from your_table
group by [user], group_id
order by [user], group_id
This achieved the desired results when I ran it, but of course because you're basing the group_id's off a user specified string length there could be issues there. I hope this does the job for you.
Give this a shot. I separated out the completed texts (and their shorter partials), and then found the longest partial for each record. Tested in Oracle as I don't have access to a PostgreSQL right now, but I didn't use anything exotic so it should work.
with
--Contains all completed searches
COMPLETE as (select * from SEARCH_TABLE where SEARCH_TEXT not like '%*'),
--Contains all searches that are incomplete and dont have a completed match
INCOMPLETE as (
select S.*
from SEARCH_TABLE S
left join COMPLETE C
on S.USR = C.USR
and C.SEARCH_TEXT like replace(S.SEARCH_TEXT, '*', '%')
where C.ID is null
),
--chains all incompleted with any matching pattern shorter than it.
CHAINED_INC as (
select LONGER.USR, LONGER.ID, LONGER.SEARCH_TEXT, SHORTER.SEARCH_TEXT SEARCH_TEXT_SHORT
from INCOMPLETE LONGER
join INCOMPLETE SHORTER
on LONGER.SEARCH_TEXT like replace(SHORTER.SEARCH_TEXT, '*', '%')
and LONGER.ID <> SHORTER.ID
)
--if a text is not the shorter text for a different record, that means it's the longest text for that pattern.
select distinct T1.USR, T1.SEARCH_TEXT
from CHAINED_INC T1
left join CHAINED_INC T2
on T1.USR = T2.USR
and T1.SEARCH_TEXT = T2.SEARCH_TEXT_SHORT
where T2.SEARCH_TEXT_SHORT is null
--finally, union back to the completed texts.
union all
select USR, SEARCH_TEXT from COMPLETE
;
Edit: removed ID from select
My Table: table1
ID Name Family
1 A AA
2 B BB
3 A AB
4 D DD
5 E EE
6 A AC
SQL command on Access:
select count(*) from table1
Output: ------------> True
6 row(s)
I tried to count unique names:
Expected output: 4 row(s)
select count(distinct Name) from table1
Output on Access: ------------> Error
What changes do I need to make to my query?
Try this
SELECT Count(*) AS N
FROM
(SELECT DISTINCT Name FROM table1) AS T;
Read this for more info.
Access-Engine does not support
SELECT count(DISTINCT....) FROM ...
You have to do it like this:
SELECT count(*)
FROM
(SELECT DISTINCT Name FROM table1)
Its a little workaround... you're counting a DISTINCT selection.
A quick trick to use for me is using the find duplicates query SQL and changing 1 to 0 in Having expression. Like this:
SELECT COUNT([UniqueField]) AS DistinctCNT FROM
(
SELECT First([FieldName]) AS [UniqueField]
FROM TableName
GROUP BY [FieldName]
HAVING (((Count([FieldName]))>0))
);
Hope this helps, not the best way I am sure, and Access should have had this built in.
Hy at all, today is the day of ...question.
I've a single table, with a relation master-detail like this:
RecordID MasterID Field1 Field2 .... NrDetail
1 0 xxx yyyy 1
2 0 aaaa bbbb 2
3 1 hhhhh ssss 0
4 2 eee sssss 0
5 2 jjj hhhh 0
As you can see, NrDetail contain the total of "child record".
Unfortunately, i've to create this field... and i would like to write it in my table.
So my SQL question is: how to do this type of SQL to write the field NrDetail ?
Something like:
UPDATE table SET NrDetail=
(SELECT COUNT(*) as Total FROM table WHERE MasterID= RecordID)
But i think there's some mistake...
Thank you in advance !
I think that you have forgetten to specify which MasterID you want to compare with which RecordID.
How about:
UPDATE table t1 SET NrDetail=
(SELECT COUNT(*) as Total FROM table t2 WHERE t1.MasterID=t2.RecordID)
UPDATE table
SET NrDetail = (
Select Count(*)
FROM table t2
Where t2.RecordID = table.MasterID
)
In an update statement, when you want to reference the table being updated, you need to use the full reference for columns(tablename.columnname, or ideally schema.tablename.columnname). If you are using the same table in a subquery, you need to alias the table in the subquery but again use the full reference for the outer table.
ADDITION Since you mentioned that you are using MySql, you could try something like so:
Update post
Join (
Select p1.idpadre, Count(*) Total
From post p1
Group By p1.idpadre
) Z
On Z.idpadre = post.idpost
Set post.NrDetail = Z.Total