How to have Counts in a Join query - sql

I have to create a join between two tables on a column and display the counts of the fields on which they are joined
For example here 'business' is my key on which i want to join.
The first query is
select
[business], count(*) as total from dimhexpand group by [business]
and I get a result as:
DA 54100
Dual 6909
ECM 1508
Flex 15481
Another query is :
select business, count (*) from LODG
group by business order by business
the result of the query is :
DA 100
Dual 909
ECM 508
Flex 15481
I want to return the data by joining these two tables to show something like
**dimhexpand.business dimhexpand.count LODG.Count**
DA 54100 100
Dual 6909 909
ECM 1508 508
Flex 15481 151481

You can JOIN the two tables on the business column:
select d.business,
count(d.business) as dimCount,
l.lodgCount
from dimhexpand d
left join
(
select business, count (*) lodgCount
from LODG
group by business
) l
on d.business = l.business
group by d.business;
If you might have different business values in each table, then you can use a FULL OUTER JOIN between both queries, similar to this:
select coalesce(d.business, l.business),
coalesce(d.dimCount, 0) dimCount,
coalesce(l.lodgCount, 0) lodgCount
from
(
select business, count(*) as dimCount
from dimhexpand
group by business
) d
full outer join
(
select business, count (*) lodgCount
from LODG
group by business
) l
on d.business = l.business

Some questions require answering to provide an accurate answer. Can you have business in dimhexpand and not in LODG or vice versa?
The subquery answer provided above will work if you will always have a one to one on business. if not, you will lose values from either table if not fully joined.
If you can have business unique to either table, can you work with memory tables?
Declare #tblDimhExpand TABLE (
business varchar(50) null,
CountDimHExpand int null
)
Declare #tblLoDG TABLE (
business varchar(50) null,
CountLodG int null
)
Insert into #tblDimhExpand select business, count(*) from DimhExpand Group By Business
Insert into #tblLoDG select business, count(*) from LODG Group By Business
Select coalesce(dim.business, lodg.business) as Business, dim.countDimhExpand, lodg.countlodg
From #tblDimhExpand dim
FULL JOIN #tblLodG lodg on dim.Business = lodg.Business
This will return all business records from both tables regardless of whether they are present on the other table, and will join the results when present in both, and give NULL for the table missing that value when they are present in only one.

Related

PostgreSQL JOIN in aggregate function

Treatment table schema
id
doctor_id
location_id
patient_id
...
I need to be able to group patient treatments based on location and list all the doctors that were treating the patient for the specific location.
SELECT id,
(SELECT STRING_AGG(t.initials::text, ',') FROM (
SELECT DISTINCT treatments.doctor_id, doctors.initials FROM
treatments LEFT JOIN doctors ON doctors.id = treatments.doctor_id) t
) as treating_doctors_initials
GROUP BY treatments.patient_id, treatments.location_id
The problem is that this returns the same initials for all records -> it does perform the join I guess or maybe I am misunderstanding the aggregate function.

How to use INTERSECT together with COUNT in SQLite?

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

What is the best way to join tables

this is more like a general question.
I am looking for the best way to join 4, maybe 5 different tables. I am trying to create a Power Bi pulling live information from an IBM AS400 where customer service can type one of our parts number,
see how many parts we have in inventory, if none, see the lead time and if there are any orders already already entered for the typed part number.
SERI is our inventory table with 37180 records.
(active inventory that is available)
METHDM is our kit table with 37459 records.
(this table contains the bill of materials for custom kits, KIT A123 contains different part numbers in it witch are in SERI as well.)
STKA is our part lead time table with 76796 records.
(lead time means how long will it take for parts to come in)
OCRI is our sales order table with 6497 records.
(This table contains all customer orders)
I have some knowledge in writing queries but this one is more challenging of what I have created in the past. Should I start with the table that has the most records and start left joining the rest ?
From STKA 76796 records
Left join METHDM 37459 records on STKA
left join SERI 37180 records on STKA
left join OCRI 6497 records on STAK
Select
STKA.v6part as part,
STKA.v6plnt as plant,
STKA.v6tdys as pur_leadtime,
STKA.v6prpt as Pur_PrepLeadtime,
STKA.v6lead as Mfg_leadtime,
STKA.v6prpt as Mfg_PrepLeadTime,
METHDM.AQMTLP AS COMPONENT,
METHDM.AQQPPC AS QTYNEEDED,
SERI.HTLOTN AS BATCH,
SERI.HTUNIT AS UOM,
(HTQTY - HTQTYC) as ONHAND,
OCRI.DDORD# AS SALESORDER,
OCRI.DDRDAT AS PROMISED
from stka
left join METHDM on STKA.V6PART = METHDM.AQPART
left join SERI on STKA.V6PART = SERI.HTPART
left join OCRI on STKA.V6PART = OCRI.DDPART
Is this the best way to join the tables?
I think you already have your answer, but conceptually, there are a few issues here to deal with, and I figured I would give you a few examples, using data a little bit like yours, but massively simplified.
CREATE TABLE #STKA (V6PART INT, OTHER_DATA VARCHAR(50));
CREATE TABLE #METHDM (AQPART INT, KIT_ID INT, SOME_DATE DATETIME, OTHER_DATA VARCHAR(50));
CREATE TABLE #SERI (HTPART INT, OTHER_DATA VARCHAR(50));
CREATE TABLE #OCRI (DDPART INT, OTHER_DATA VARCHAR(50));
INSERT INTO #STKA SELECT 1, NULL UNION ALL SELECT 2, NULL UNION ALL SELECT 3, NULL; --1, 2, 3 Ids
INSERT INTO #METHDM SELECT 1, 1, '20200108 10:00', NULL UNION ALL SELECT 1, 2, '20200108 11:00', NULL UNION ALL SELECT 2, 1, '20200108 13:00', NULL; --1 Id appears twice, 2 Id once, no 3 Id
INSERT INTO #SERI SELECT 1, NULL UNION ALL SELECT 3, NULL; --1 and 3 Ids
INSERT INTO #OCRI SELECT 1, NULL UNION ALL SELECT 4, NULL; --1 and 4 Ids
So fundamentally we have a few issues here:
o the first problem is that the IDs in the tables differ, one table has an ID #4 but this isn't in any of the others;
o the second issue is that we have multiple rows for the same ID in one table;
o the third issue is that some tables are "missing" IDs that are in other tables, which you already covered by using LEFT JOINs, so I will ignore this.
--This will select ID 1 twice, 2 once, 3 once, and miss 4 completely
SELECT
*
FROM
#STKA
LEFT JOIN #METHDM ON #METHDM.AQPART = #STKA.V6PART
LEFT JOIN #SERI ON #SERI.HTPART = #STKA.V6PART
LEFT JOIN #OCRI ON #OCRI.DDPART = #STKA.V6PART;
So the problem here is that we don't have every ID in our "anchor" table STKA, and in fact there's no single table that has every ID in it. Now your data might be fine here, but if it isn't then you can simply add a step to find every ID, and use this as the anchor.
--This will select each ID, but still doubles up on ID 1
WITH Ids AS (
SELECT V6PART AS ID FROM #STKA
UNION
SELECT AQPART AS ID FROM #METHDM
UNION
SELECT HTPART AS ID FROM #SERI
UNION
SELECT DDPART AS ID FROM #OCRI)
SELECT
*
FROM
Ids I
LEFT JOIN #STKA ON #STKA.V6PART = I.Id
LEFT JOIN #METHDM ON #METHDM.AQPART = I.Id
LEFT JOIN #SERI ON #SERI.HTPART = I.Id
LEFT JOIN #OCRI ON #OCRI.DDPART = I.Id;
That's using a common-table expression, but a subquery would also do the job. However, this still leaves us with an issue where ID 1 appears twice in the list, because it has multiple rows in one of the sub-tables.
One way to fix this is to pick the row with the latest date, or any other ORDER you can apply to the data:
--Pick the best row for the table where it has multiple rows, now we get one row per ID
WITH Ids AS (
SELECT V6PART AS ID FROM #STKA
UNION
SELECT AQPART AS ID FROM #METHDM
UNION
SELECT HTPART AS ID FROM #SERI
UNION
SELECT DDPART AS ID FROM #OCRI),
BestMETHDM AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY AQPART ORDER BY SOME_DATE DESC) AS ORDER_ID
FROM
#METHDM)
SELECT
*
FROM
Ids I
LEFT JOIN #STKA ON #STKA.V6PART = I.Id
LEFT JOIN BestMETHDM ON BestMETHDM.AQPART = I.Id AND BestMETHDM.ORDER_ID = 1
LEFT JOIN #SERI ON #SERI.HTPART = I.Id
LEFT JOIN #OCRI ON #OCRI.DDPART = I.Id;
Of course you could also add some aggregation (SUM, MAX, MIN, AVG, etc.) to fix this problem (if it is indeed an issue). Also, I used a common-table expression, but this would work just as well with a subquery.
Expanding on a comment made on the question..
I would say I will start with SERI as that table contains the entire inventory for our facility and should cover the other tables
However the question said
SERI is our inventory table with 37180 records. (active inventory that is available)
In my experience, active inventory, isn't the same as all parts.
Normally, in a query like this, I'd expect the first table to be a Parts Master table of some sort that contains every possible part ID.

Referential integrity between tables in SQL Server

I have 2 tables, Members and Enrollments. Both tables can be joined using primary key Member ID.
I need to write a query which returns all the members in the Members table which don't have a corresponding row in the Enrollments table and vice versa.
This is what I have so far:
IF OBJECT_ID('tempdb..#memberswithoutenrollments') IS NOT NULL
DROP TABLE #memberswithoutenrollments
SELECT m.*
INTO #memberswithoutenrollments
FROM ABC_Members m
LEFT OUTER JOIN ABC_MemEnrollment e ON m.MemberID = MemberID
FULL JOIN is a simple method for comparing lists between two tables:
SELECT COALESCE(e.MemberID, m.MemberID),
(CASE WHEN e.MemberID IS NULL THEN 'No Enrollments' ELSE 'No Member' END)
FROM ABC_Members m FULL JOIN
ABC_MemEnrollment e
ON m.MemberID = e.MemberID
WHERE e.MemberID IS NULL OR m.MemberID IS NULL;
But if you have proper foreign key relationships, then you should never have enrollments without members.
You can use NOT IN to your benefit here.
WITH
-- Create a list of all of the matches
in_table AS
(
SELECT
Member_ID
FROM
Enrollments
WHERE
Members.MemberID = Enrollments.Member_ID
),
result_table AS
(
SELECT
*
FROM
Members
-- Grab only the values from members that DO NOT APPEAR in in_table
WHERE
MemberID NOT IN (SELECT DISTINCT FROM in_table)
)
-- Grab all results
SELECT * FROM result_table

SQL Query – records within the SQL Select statement, but NOT in the table being queried

I have a large list of CustIDs that I need to query on to find if they are within the CUSTOMER table; I want the result to tell me which CustIDs ARE on the table and which CustIDs are NOT on the table.
I provided a short list below to give an idea of what I need to do.
Oracle database
Table: Customer
Primary Key: CustID
Scenario:
Customer table only has the following (2) CustID: ‘12345’, ‘56789’
Sql:
Select * from CUSTOMERS where CUSTID in (‘12345’, ‘56789’, ‘01234’);
I want the result to tell me that both ‘12345’ and ‘56789’ are in the table, AND that ‘01234’ is NOT.
select
v.CustID,
exists (select * from Customer where Customer.CustID = v.CustID)
from (values (12345), (56789), (01234)) v (CustID);
Results:
custid exists
12345 true
56789 true
1234 false
You need a left join or subquery for this. The precise syntax varies by database. Typical syntax is:
select i.custid,
(case when c.custid is not null then 1 else 0 end) as exists_flag
from (select '12345' as custid union all
select '56789' union all
select '01234'
) ci left join
customers c
on c.cust = i.custid;