I need a SQL query for comparing column values against rows in the same table - sql

I have a table called BB_BOATBKG which holds passengers travel details with columns Z_ID, BK_KEY and PAXSUM where:
Z_ID = BookingNumber* LegNumber
BK_KEY = BookingNumber
PAXSUM = Total number passengers travelled in each leg for a particular booking
For Example:
Z_ID BK_KEY PAXSUM
001234*01 001234 2
001234*02 001234 3
001287*01 001287 5
001287*02 001287 5
002323*01 002323 7
002323*02 002323 6
I would like to get a list of all Booking Numbers BK_KEY from BB_BOATBKG where the total number of passengers PAXSUM is different in each leg for the same booking
Example, For Booking number A, A*Leg01 might have 2 Passengers, A* Leg02 might have 3 passengers

Dependent of your RDBMs there might be several options availible. A solution that should work for most is:
SELECT A.Z_ID, A.BK_KEY, A.PAXSUM
FROM BB_BOATBKG A
JOIN (
SELECT BK_KEY
FBB_BOATBKGROM BB_BBK_KEY
GROUP BY BK_KEY
HAVING COUNT( DISTINCT PAXSUM ) > 1
) B
ON A.BK_KEY = B.BK_KEY
If your DBMS support OLAP functions, have a look at RANK() OVER (...)

It's a little counterintuitive, but you could join the table to itself on {BK_KEY, PAXSUM} and pull out only the records whose joined result is null.
I think this does it:
SELECT
a.BK_KEY
FROM
BB_BOATBKG a
LEFT OUTER JOIN BB_BOATBKG b ON a.BK_KEY = b.BK_KEY AND a.PAXSUM = b.PAXSUM
WHERE
b.Z_ID IS NULL
GROUP BY
a.BK_KEY
Edit: I think I missed anything beyond the trivial case. I think you can do it with some really nasty subselecting though, a la:
SELECT
b.BK_KEY
FROM
(
SELECT
a.BK_KEY,
Count = COUNT(*)
FROM
(
SELECT
a.BK_KEY,
a.PAXSUM
FROM
BB_BOATBKG a
GROUP BY
a.BK_KEY,
a.PAXSUM
HAVING
COUNT(*) = 1
) a
GROUP BY
a.BK_KEY
) b
INNER JOIN
(
SELECT
c.BK_KEY,
Count = COUNT(*)
FROM
BB_BOATBKG c
GROUP BY
c.BK_KEY
) c ON b.BK_KEY = c.BK_KEY AND b.Count = c.Count

Related

Having trouble understand which table is count(*) actually counting when joining two tables together.

If I have the following codes, which table is count(*) counting the number or rows in it?
SELECT COUNT(*)
FROM region r
JOIN sales_rep s
ON r.id = s.region_id
Thanks a lot!!!
It is counting the rows from your join query as a whole. It is the same as:
SELECT COUNT(*)
FROM
(SELECT * FROM region r
JOIN sales_rep s
ON r.id = s.region_id)
It is counting all records of the "resulting" table from the join. The number will depend on the type of relationship between region and sales_rep. Assuming your domain is that a region has zero or many sales_rep and that all sales_rep have one and only one region then the count will always equals to the count of sales_rep. For example:
regions: (id) sales_rep: (id, reg_id)
A 1 A
B 2 A
C 3 B
4 C
count(*) = 4
On the other hand if a sales_rep can have no region then the ones with no region are excluded:
regions: (id) sales_rep: (id, reg_id)
A 1 A
B 2 null
C 3 B
4 C
count(*) = 3
Or if a sales_rep can have more than one region then the result is the same as 1st case but you will have a higher count:
regions: (id) sales_rep: (id, reg_id)
A 1 A
B 1 B
C 2 A
3 B
4 C
count(*) = 5
I'd definitely recommend you to do a select * so you can see by yourself whats happening and then change it to count. Additionally please refer to this article to better understand joints: https://www.w3schools.com/sql/sql_join.asp

How to group results by count of relationships

Given tables, Profiles, and Memberships where a profile has many memberships, how do I query profiles based on the number of memberships?
For example I want to get the number of profiles with 2 memberships. I can get the number of profiles for each membership with:
SELECT "memberships"."profile_id", COUNT("profiles"."id") AS "membership_count"
FROM "profiles"
INNER JOIN "memberships" on "profiles"."id" = "memberships"."profile_id"
GROUP BY "memberships"."profile_id"
That returns results like
profile_id | membership_count
_____________________________
1 2
2 5
3 2
...
But how do I group and sum the counts to get the query to return results like:
n | profiles_with_n_memberships
_____________________________
1 36
2 28
3 29
...
Or even just a query for a single value of n that would return
profiles_with_2_memberships
___________________________
28
I don't have your sample data, but I just recreated the scenario here with a single table : Demo
You could LEFT JOIN the counts with generate_series() and get zeroes for missing count of n memberships. If you don't want zeros, just use the second query.
Query1
WITH c
AS (
SELECT profile_id
,count(*) ct
FROM Table1
GROUP BY profile_id
)
,m
AS (
SELECT MAX(ct) AS max_ct
FROM c
)
SELECT n
,COUNT(c.profile_id)
FROM m
CROSS JOIN generate_series(1, m.max_ct) AS i(n)
LEFT JOIN c ON c.ct = i.n
GROUP BY n
ORDER BY n;
Query2
WITH c
AS (
SELECT profile_id
,count(*) ct
FROM Table1
GROUP BY profile_id
)
SELECT ct
,COUNT(*)
FROM c
GROUP BY ct
ORDER BY ct;

How can I show all "article" which have more than 3 "bids"?

I wanna show the "ArticleName" of all "offers" that have more than 3 "bids". The number of the "Bids" should be output.
I don't know how I can write it down. But I think I know the Logic. It should count the same number of the Table "bid" and the column "OID" and in the end it should paste the number which is more than 3.
Picture:
Well that's easy enough:
Select ArticleName
, count(*) NumberOfBids
from Offer o
join Bid b
on b.oid = o.oid
group by ARticleName
having count(*) >= 3
SELECT * FROM (
SELECT o.ArticleName, count(b.BID) as numberOfBids
FROM Offer as o INNER JOIN bid as b ON o.oid = b.oid
GROUP BY o.ArticleName
) as c
WHERE c.numberOfBids > 3

SQL joining two tables with common row

I have 2 tables in sybase
Account_table
Id account_code
1 A
2 B
3 C
Associate_table
id account_code
1 A
1 B
1 C
2 A
2 B
3 A
3 C
I have this sql query
SELECT * FROM account_table account, associate_table assoc
WHERE account.account_code = assoc.account_code
This query will return 7 rows. What I want is to return the rows from associate_table that is only common to the 3 accounts like this:
account id account_code Assoc Id
1 A 1
2 B 1
3 C 1
Can anyone help what kind of join should I do?
SELECT b.id account_id,a.code account_code,a.id assoc_id
FROM associate a,
account b
WHERE a.code = b.code
AND a.id IN (SELECT a.id
FROM associate a,
account b
WHERE a.code = b.code
GROUP BY a.id
HAVING Count(*) = (SELECT Count(*)
FROM account));
NOTE: this query works only if you have unique values in Id and account_code columns in account table. And also, your associate_table should contain unique combination of (id, account,code). i.e., associate table should not contain (1,A) or any pair twice.
Try this
SELECT AC.ID,AC.account_code,ASS.ID
FROM account_table AC INNER JOIN associate_table AS ASS ON AC.account_code = ASS.account_code
OK so far answer is accepted I'll post simpler one:
SELECT *
FROM account_table AS account,
associate_table AS assoc
WHERE account.account_code = assoc.account_code
HAVING (
SELECT
COUNT(*)
FROM associate_table assoc_2
WHERE assoc_2.id = assoc.id
) = 3
here 3 is the number of codes account table has, if it's gonna be dynamic (changing over time),
you can use (SELECT COUNT(*) FROM account_table) instead of exact number. Also I'm sure it will be cached by database engine, so requires less resources

Help construct a query given a schema

Here is the schema for the database: http://i.stack.imgur.com/omX60.png
Question is: How many people have at least five еntitlements?
I've got this, please tell me how wrong it is and fix it.
select count(personId)
from serialNumber_tbl natural join entitlement_tbl
group by personId
having sum(entitlementID) > 5
Thank you.
The condition for at least 5 is >= 5, not > 5
You need to count the distinct ids in the entitlement table, not person
This gives you the persons, next you need to subquery it to find the count of persons.
select count(personId)
FROM
(
select personId
from serialNumber_tbl natural join entitlement_tbl
group by personId
having count(distinct entitlement_id) >= 5
) X
Your request isn't exactly clear. Are you asking for the count of people with more than five entitlement rows whether they exist on multiple serial numbers or not? If so, you could do something like:
Select Count(*) As CountOfPeople
From Person_tbl As P
Where Exists (
Select 1
From serialNumbers As S1
Join entitlement_tbl As E1
On E1.serialNumberId = S.serialNumberId
Where S1.personId = P.personId
Having Count(*) >= 5
)
Or is it that you are asking to find the number of people that have a serialNumber with more than five entitlements? If that is the case, then you could do something like:
Select Count(*) As CountOfPeople
From Person_tbl As P
Where Exists (
Select 1
From serialNumbers As S1
Join entitlement_tbl As E1
On E1.serialNumberId = S.serialNumberId
Where S1.personId = P.personId
Having Count( Distinct S1.serialNumberId ) >= 5
)