How to use INTERSECT together with COUNT in SQLite? - sql

I have a table called customer_transactions and a table called blacklist.
The customer_transactions table has a column called atm_name.
Both tables share a unique key called id.
How can I intersect the two tables in such a way that the query shows me
customers that appear on both tables.
a corresponding column that displays the times that they had used a
certain atm alongside the atm's name
(for instance: id_1 -- bank of america -- 2; id_1 -- citibank -- 3;
id_2 -- bank of america -- 1; id_2 -- citibank -- 4, etcetera).
I have something like this
SELECT id,
atm_name,
count(atm_name) as atm_count
FROM customer_transactions
GROUP BY id, atm_name
How can I INTERSECT this table with the blacklist table and maintain what I currently have as output?
Thanks in advance.

You seem to want a join. Assuming that column id relates the two tables, and that it is a unique key in blacklist, you can do:
select ct.id, ct.atm_name, count(*) as atm_count
from customer_transactions ct
inner join blacklist b on b.id = ct.id
group by ct.id, ct.atm_name
You can also express this logic with exists and a correlated subquery:
select ct.id, ct.atm_name, count(*) as atm_count
from customer_transactions ct
where exists (select 1 from blacklist b where b.id = ct.id)
group by ct.id, ct.atm_name

Related

Select columns based on count of many-to-many association

I have a Postgres database with 3 tables that looks a little something like this:
table categories
id
type
table games
id
table game_category
id
game_id
category_id
I want to select all games which have more than x categories where type is something
I have gotten this far:
SELECT * FROM games WHERE id IN (
SELECT game_id FROM game_category GROUP BY game_id HAVING COUNT(*) >= 5
)
This works to select all games with more than 5 categories, but doesn't narrow down the categories by their type. How could I expand on this to add the additional check for the type?
You have to join your categories table with the subquery. Then you can add a WHERE clause for the type. Replace '?' with your actual type, of course.
SELECT * FROM games WHERE id IN (
SELECT game_id FROM game_category
INNER JOIN categories ON (categories.id=game_category.category_id)
WHERE categories.type='?'
GROUP BY game_id HAVING COUNT(*) >= 5
)
Considering query response time, you can avoid the in clause. Mitchel's answer would work if written as follows:
SELECT game_id
FROM game_category gc
inner join categories c on c.id = gc.category_id
WHERE type = 'X'
GROUP BY game_id
HAVING COUNT(game_id) >= 5
Notice I avoided using count(*) that is also a query optimization strategy

Sum and Join Two tables in Oracle

I have two tables: Base table and Detail table. I need to get the count from the Detail table with Base table.
Tables structure
Base table
Nid UserId BaseVal
--------------------
1 150 100
Detail table
Did Nid SeqVal
----------------
1 1 500
2 1 600
I want this:
Result Table
BaseVal SeqVal
---------------
100 1100
I have tried this query but I can get only the Summation value. I need BaseVal too.
SELECT SUM(SeqVal) as SEQVAL
FROM TBL_DETAIL
WHERE Nid =: Nid
You have to join tables first and then calculate the sum:
select b.nid, b.baseVal, sum(d.seqVal)
from base_table b join detail_table d on b.nid = d.nid
where b.nid =: Nid
group by b.nid, b.baseVal
There are multiple answers possible. Assuming your base table always has 1 record and detail table has multiple rows per base table record, a possible answer can be
SELECT
AVG(BaseVal) Sum_BaseVal, SUM(SeqVal) Sum_SeqVal
From BaseTable T1, DetailTable T2
WHERE T1.Nid = T2.Nid
AND T1.Nid = :1
Bind T1.Nid with right value to ensure you get values for required Nid.
Note: You can also use above query with a GROUP BY Nid (it may be necessary if your problem statement is simplified version of a complex query)
Other possible answers can be (I'm giving only 1 to save time, but more exists)
WITH
SeqSum as (SELECT SUM(SeqVal) Sum_SeqVal FROM DetailTable WHERE Nid = 1)
SELECT BaseVal, Sum_SeqVal
FROM BaseTable , SeqSum
WHERE Nid = 1
You can further tune queries to have proper conditions if any..

Update multiple row values to same row and different columns

I was trying to update table columns from another table.
In person table, there can be multiple contact persons with same inst_id.
I have a firm table, which will have latest 2 contact details from person table.
I am expecting the firm tables as below:
If there is only one contact person, update person1 and email1. If there are 2, update both. If there is 3, discard the 3rd one.
Can someone help me on this?
This should work:
;with cte (rn, id, inst_id, person_name, email) as (
select row_number() over (partition by inst_id order by id) rn, *
from person
)
update f
set
person1 = cte1.person_name,
email1 = cte1.email,
person2 = cte2.person_name,
email2 = cte2.email
from firm f
left join cte cte1 on f.inst_id = cte1.inst_id and cte1.rn = 1
left join cte cte2 on f.inst_id = cte2.inst_id and cte2.rn = 2
The common table expression (cte) used as a source for the update numbers rows in the person table, partitioned by inst_id, and then the update joins the cte twice (for top 1 and top 2).
Sample SQL Fiddle
I think you don't have to bother yourself with this update, if you rethink your database structure. One great advantage of relational databases is, that you don't need to store the same data several times in several tables, but have one single table for one kind of data (like the person's table in your case) and then reference it (by relationships or foreign keys for example).
So what does this mean for your example? I suggest, to create a institution's table where you insert two attributes like contactperson1 and contactperson2: but dont't insert all the contact details (like email and name), just the primary key of the person and make it a foreign key.
So you got a table 'Person', that should look something like this:
ID INSTITUTION_ID NAME EMAIL
1 100 abc abc#inst.com
2 101 efg efg#xym.com
3 101 ijk ijk#fg.com
4 101 rtw rtw#rtw.com
...
And a table "Institution" like:
ID CONTACTPERSON1 CONTACTPERSON2
100 1 NULL
101 2 3
...
If you now want to change the email adress, just update the person's table. You don't need to update the firm's table.
And how do you get your desired "table" with the two contact persons' details? Just make a query:
SELECT i.id, p1.name, p1.email, p2.name, p2.email
FROM institution i LEFT OUTER JOIN person p1 ON (i.contactperson1 = p1.id)
LEFT OUTER JOIN person p2 ON (i.contactperson2 = p2.id)
If you need this query often and access it like a "table" just store it as a view.

Taking Unique Records From Two Tables

i am stuck at a silly problem. And it has to be one of the most cliche solution.
Table student_selection:
Columns
=======
student_id
subject_id
faculty_id
Another table: sub_group
Columns
=======
subject_id
sub_group
They are Joint on subject_id.
I want to find those subject_id from table sub_group where, the subject_id is not present in the student_selection table.
Eg:
sub_group(subject_id)
2
3
4
student_selection(subject_id)
2
3
2
3
2
3
Output
4
You can run a simple not in query to get the data.
Like:
SELECT
subject_id
FROM
sub_group
WHERE
subject_id not in (
SELECT
DISTINCT subject_id
FROM
student_selection
)
Standard SQL IN clause:
select subject_id from sub_group
where subject_id not in (select subject_id from student_selection);
Standard SQL EXISTS clause:
select subject_id from sub_group sg
where not exists
(select * from student_selection ss where ss.subject_id = sg.subject_id);
Set based query. Some dbms support set based operations. They use the word EXCEPT or MINUS to subtract one set from another. (MySQL doesn't support this.)
select subject_id from sub_group
except
select subject_id from student_selection;
At last you can use a trick where you outer join the second table and only stay with those results where there was a record outer-joined (i.e. there is no macthing record in the second table). This is also standard SQL. It is less readable for the unexperienced reader but happens to be faster on some dbms.
select sg.subject_id
from sub_group sg
left join student_selection ss on ss.subject_id = sg.subject_id
where ss.subject_id is null;

primary table joined to foreign table - select only one record from foreign table

Using SQL Server 2012. I have a table called deals that contains a primary key called deal_id along with 10 other fields. I also have a table called deals_country that contain a foreign key called deal_id.
It's possible that a record in deals contains numerous records in deals country. I know the query below will return all the records for the two tables.
select deals .*, deals_country.* from deals inner join deals_country
on deals .deal_id = deals_country.deal_id
order by deals .deal_id
What I would like to do is select all the records from deals and select only one corresponding record from the deals_country table, it doesn't matter which record it takes from deals_country. Something like below,
Deals
deal_id other fields
MN13
MN14
MN15
MN28
Deals_Country
deal_id country
MN13 NL
MN13 FR
MN14 GB
MN14 US
MN15 US
MN28 CA
MN28 US
MN28 MX
The result I would like see,
deal_id country
MN13 NL
MN14 GB
MN15 US
MN28 CA
You can use cross apply for this:
select d.*, dc.*
from deals d cross apply
(select top 1 dc.*
from deals_country dc
where d.deal_id = dc.deal_id
) dc
order by d.deal_id;
You can enumerate the deals_country rows per deal and select the first (whatever that is):
select ...
from (
select ...
, row_number() over (partition by deals.deal_id) as rn
from deals
join deals_country
on deals.deal_id = deals_country.deal_id
) as T
where rn = 1;
Untested, but you should get the idea