How to get what percentage of total users joined what number of meetings in PostgreSQL? - sql

There are two tables, one is called "user_preference" that contains all users:
id | firstname | lastname | email |
And "match" which combines users with meetups they joined:
id | matcher | partner | meetup |
Both matcher and partner are foreign keys that represent user_preference.id, meaning that same user can be both matcher and a partner in the same meetup.
What I need to know is what percentage of total unique users joined what number of meetings.
For example:
17% of users joined 5 meetups
20% of users joined 3 meetups
40% of users joined 1 meetup
23% of users joined 0 meetups
The number of meetups should not be hardcoded but dynamic.
But I want to avoid duplication of users for a single meetup and count them only once. For example this:
id | matcher | partner | meetup |
1 | user1 | user2 | meetup1 |
2 | user1 | user3 | meetup1 |
3 | user5 | user1 | meetup1 |
4 | user6 | user1 | meetup2 |
Should count that user1 visited only 2 meetups.
What I managed to do so far is to display the count of meetups each user visited but that is not what I need:
SELECT distinct up.email users, COUNT(m.user) meetups
FROM user_preference up
LEFT JOIN
(
SELECT matcher AS user FROM match
UNION ALL
SELECT partner AS user FROM match
) m ON m.user = up.id
GROUP BY up.email
ORDER BY meetups desc;

In the end I did this by making simple queries and looping through them in the code, its far from elegant solution but it should work.
If someone posts SQL solution I will accept and upvote it...
export const getDevStats = async () => {
const users = await getRepository(UserPreference).query(
`SELECT * FROM user_preference;`
);
const meetups = await getRepository(Meetup).query(
`SELECT * FROM meetup;`
);
const matches = await getRepository(Match).query(
`SELECT * FROM match;`
);
let userMatches: any = {};
users.forEach((user: any) => {
userMatches[user.id] = []
matches.forEach((match: any) => {
if(user.id == match.matcher || user.id == match.partner) {
if(userMatches[user.id].indexOf(match.meetup) === -1) {
userMatches[user.id].push(match.meetup);
}
}
});
});
let matchStats: any = {};
for (var userId of Object.keys(userMatches)) {
if (typeof matchStats[userMatches[userId].length] === 'undefined') {
matchStats[userMatches[userId].length] = 0;
}
matchStats[userMatches[userId].length]++;
}
return {
users: users,
meetups: meetups,
matches: matches,
userMatches: userMatches,
matchStats: matchStats
};
};

Related

TypeScript Sequelize : How to join two tables with common

There are three tables.
Tables :
Trip
id | start_destination_id | end_destination_id | arrive_time |
-------------------------------------------------------------------
1 | S | E | 09:00 |
Destination
id | name
---------
S | Start
E | End
Schedule
id | start_destination_id | end_destination_id | should_arrive |
-------------------------------------------------------------------
1 | S | E | 08:00 |
2 | A | E | 10:00 |
Query
SELECT
Trip.*,
Schedule.should_arrive
FROM
Trip
LEFT JOIN
Schedule
ON
Trip.start_destination_id = Schedule.start_destination_id
AND
Trip.end_destination_id = Schedule.end_destination_id
I am trying to include Schedule in Trip.findAll but receive error
Exception: SequelizeEagerLoadingError: Schedule is not associated to Trip!
Is there a way that I can join them together without using foreign keys and raw queries?
Many thanks.
Finally I found a solution (not sure if it is a hack).
Schedule.ts
// add these lines
...
#ForeignKey(() => Trip)
#Column({ type: DataType.VIRTUAL })
private _dummyForTrip: undefined;
...
Then create an association between Schedule and Trip.
Trip.ts
#HasMany(() => Schedule)
public schedules: Schedule[] | null
Then you can include Schedule inside Trip by using include.on
const trips = await Trip.findAll({
include: [{
model: Schedule,
on: {
'$schedules.start$': { [Op.col]: "Trip.start_destination" },
'$schedules.end$': { [Op.col]: "Trip.end_destination" },
}
}],
where: {
id: { [Op.in]: payload.inputTripIdArr }
}
});

Linq-like group by for sql

It seems like sql group by is more of aggregate functions (COUNT, MAX, MIN, SUM, AVG).
select count(Id), Country
from Customer
where Country <> 'CountryX'
group by Country
But do we have a linq-like query where we want to return all results grouped by a certain column, E.g. in linq I would do
id | title | category | email
------------------------------------------
1 | tname-1 | cat1 | test#example.com
2 | tname-2 | cat1 | test1#example.com
3 | tname-3 | cat2 | TEst#example.com
linq group-by:
var groupedBy = list.GroupBy(item => item.Email);
or even throw in some comparison
var groupedBy = list.GroupBy(item => item.Email, StringComparer.OrdinalIgnoreCase);
and a result will be something like:
key | items
----------------------------------------------------------------------------------------------
test#example.com | [{Id :1, Title : "tname-1", category: "cat1", email: "test#example.com" },{Id :3, Title : "tname-3", category: "cat2", email: "TEst#example.com" } ]
test1#example.com| [{Id :2, Title : "tname-2", category: "cat1", email: "test1#example.com" }]
but with sql I would definitely want to return only the subset of the columns, say id, title and email.

Codeigniter merge into one row record with sql one to many relationship

I would like to query one to many relationship
eg:
Table A: Table B:
id | country_name id | name | table_A_id
1 | Usa 1 | kerry | 1
2 | Australia 2 | jerry | 1
3 | tommy | 2
4 | cherry | 2
my purpose is to query the result to merge one row record
eg: result list:
1 Record 2 Record
Usa Australia
kerry tommy
jeryy cherry
Currently, I am using Codeignter framework and beginner for sql, please don't mind me guys.
$this->db->select('*')
>from("table A")
->join("table B", "table.A.id = table_A_id");
$query = $this->db->get();
if($query->num_rows() > 0) {
return $query->result();
}
My view
<?php foreach($posts as $post) {
echo $post->country_name;
echo $post->name;
} ?>
However, it gives me 4 row records.
1 Record 2 Record
Usa Usa
kerry jerry
3 Record 4 Record
Australia Australia
tommy cherry
Thanks you guys in advance for helping me.
Here is what you missed
$this->db->select('*')
>from("table A")
->join("table B", "table.A.id = table_A_id");
$query = $this->db->get();
if($query->num_rows() > 0) {
return $query->result();
}
it should have been
->join("table B", 'B.table_A_id=A.id');
hope this make sense
option B
$this->db->join('table B','B.table_A_id=A.id','INNER');
$query = $this->db->get('table A');
Try out this
SELECT country, group_concat(name) FROM city c INNER JOIN employee e
ON c.id = e.city_id group by c.id
output
('USA ' , 'jerry ,kerry'),
('Australia', 'cherry ,tommy');
My solution found without using inner join:
public function mergeRecord() {
$array_store = array();
foreach($this->one() as $row) {
$child = $this->many($row['id']);
if($child) {
$return = array_merge(array("parent" => $row), array("child" =>$child));
array_push($array_store, $return);
}
}
return $array_store;
}
public function one() {
$query = $this->db->select("*")
->get("table A")
->result_array();
return $query;
}
public function many($id) {
$query = $this->db->select("id, name")
->where("table_A_id", $id)
->get("table B")
->result_array();
return $query;
}

filter data with entity framework

I'm trying to get the right data
Rooms table
Id | Name
1 Room1
2 Room2
Resources table
Id | Name
1 Resource1
2 Resource2
3 Resource3
RoomResources table
Id | RoomId | ResourceId
1 1 1
2 1 2
3 1 3
4 2 2
5 2 3
I want select a room with Resource1 and Resource2
I'm using this code
int[] ids = sResources.Split(',').Select(s => int.Parse(s)).ToArray();
rooms = from r in context.Rooms
where r.Area.Office.Id == officeId
&& r.MaximumPeople >= numberOfPeople
&& r.RoomResources.Any(s => ids.Contains(s.ResourceId))
select r;
but it return Room1 and Room2 and the result should be Room1
Maybe this?
int[] ids = sResources.Split(',').Select(s => int.Parse(s)).ToArray();
rooms = from r in context.Rooms
where r.Area.Office.Id == officeId
&& r.MaximumPeople >= numberOfPeople
&& ids.All(i => r.RoomResources.Any(s => s.ResourceId == i)) // try this here
select r;

entity framework distinct by field

i have table kopija that goes like this:
idKopija | idFilm | nije_tu
1 | 1 | 0
2 | 1 | 0
3 | 1 | 1
4 | 2 | 1 and etc.
And i have query that goes like this:
var upit = from f in baza.films
join z in baza.zanrs on f.idZanr equals z.idZanr
join k in baza.kopijas on f.idFilm equals k.idFilm
select new
{
idFilm = f.idFilm,
nazivFilm = f.naziv,
nazivZanr = z.naziv,
idZanr = f.idZanr,
godina = f.godina,
slika = f.slika,
klip = f.klip,
nijeTu = k.nije_tu
};
if (checkBox1.Checked)
upit = upit.Where(k => k.nijeTu == 0).Distinct();
else
{
upit = upit.Where(k => k.nijeTu == 0 || k.nijeTu == 1).Distinct();
}
Now i want to make a distinct list of "idFilm". But prolem is that I get idFilm on two places because one of them has nije_tu=0 and other one has nije_tu=1.
Please someone help me.
Thank you.
What about
upit.Where(k => k.nijeTu == 0 || k.nijeTu == 1).Select(x => x.idFilm).Distinct();
?