MySQL intersection in subquery - sql

I'm trying to create a filter for a list (of apartments), with a many-to-many relationship with apartment features through the apartsments_features table.
I would like to include only apartments that have all of some features (marked 'Yes' on a form) excluding all the ones that have any of another set features (marked 'No'). I realized too late that I couldn't use INTERSECT or MINUS in MySQL.
I have a query that looks something like:
SELECT `apartments`.* FROM `apartments` WHERE `apartments`.`id` IN (
SELECT `apartments`.`id` FROM `apartments` INTERSECT (
SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 103
INTERSECT SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 106
) MINUS (
SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 105 UNION
SELECT `apartment_id` FROM `apartments_features` WHERE `feature_id` = 107)
)
ORDER BY `apartments`.`name` ASC
I'm pretty sure there's a way to do this, but at the moment my knowledge is restricted to little more than simple left and right joins.

A slightly different way of doing it:
select a.*
from apartments a
join apartments_features f1
on a.apartment_id = f1.apartment_id and f1.feature_id in (103,106) -- applicable features
where not exists
(select null from apartments_features f2
where a.apartment_id = f2.apartment_id and f2.feature_id in (105,107) ) -- excluded features
group by f1.apartment_id
having count(*) = 2 -- number of applicable features

You could try something like this:
SELECT apartment_id
FROM
(
SELECT apartment_id
FROM apartments_features
WHERE feature_id IN (103, 106)
GROUP BY apartment_id
HAVING COUNT(*) = 2
) T1
LEFT JOIN
(
SELECT apartment_id
FROM apartments_features
WHERE feature_id IN (105, 107)
) T2
ON T1.apartment_id = T2.apartment_id
WHERE T2.apartment_id IS NULL
Join the result of this query to the apartments table to get the name, etc.

Related

T-SQL Query - how to create a new temporary "location" in a table under a location column that combines other location data

While running a query that selects a Location, date, and visitIDs, I need to be able to select a new combined location name (eg. "LOC3+4") which includes all the rows from locations "LOC3" and "LOC4". This new dataset need to have its own location name so that I can group the data by Location in an SSRS report.
Simplified Query - EDITED to add joins and subqueries-- the combined location that doesn't exist yet.
SELECT subq1.Date, subq1.Location, Count(subq1.VisitID)
FROM
(SELECT t1.Date, t1.Location, t1.VisitID
FROM table t1 LEFT OUTER JOIN
table t2 ON t2.VisitID = t1.VisitID LEFT OUTER JOIN
table t3 ON t3.ClientID = t2.ClientID
(etc)
WHERE t1.FacID = FAC1 AND t1.Status = 'Adm') subq1
WHERE subq1.Location = 'LOC1' AND subq1.Room NOT IN ('Room1','Room2',etc....)
UNION ALL
-- repeat for LOC2-5
UNION ALL
(not sure how to do the combined location)
Expected Results (includes combined location with expected result)
To Expand on GMB's answer, I think you need one or more UNIONS in the cross apply to include both the original and the mapped locations.
select t.date, x.location, count(*) cnt
from mytable t
cross apply (
select location
union all
select 'LOC3-4' AS location where t.location in ('LOC3', 'LOC4')
union all
select 'LOC2-5' AS location where t.location in ('LOC2', 'LOC3', 'LOC4', 'LOC5')
) x
group by t.date, x.location
A better solution may be to use a table driven mapping that associates original locations with mapped/combined locations.
declare #mapping table (location varchar(10), mapped_location varchar(10))
insert #mapping
values
('LOC3', 'LOC3-4'),('LOC4', 'LOC3-4'),
('LOC2', 'LOC2-5'),('LOC3', 'LOC2-5'),('LOC4', 'LOC2-5'),('LOC5', 'LOC2-5')
select t.date, x.location, count(*) cnt
from mytable t
cross apply (
select location
union all
select m.mapped_location as location
from #mapping m
where m.location = t.location
) x
group by t.date, x.location
If there are no matching entries, you only count the original location. The mapping can also define multiple mapped locations for a single source location.
Both of the above generate results like:
date
location
cnt
2022-10-31
LOC1
1
2022-10-31
LOC2
2
2022-10-31
LOC2-5
14
2022-10-31
LOC3
3
2022-10-31
LOC3-4
7
2022-10-31
LOC4
4
2022-10-31
LOC5
5
(using abbreviated test data)
See this db<>fiddle for a demo.
You can use a conditional expression to assign the new location. In SQL Server, it is handy to do this in cross apply :
select t.date, x.new_location, count(*) cnt
from mytable t
cross apply ( values
(case when location in ('LOC3', 'LOC4') then 'LOC3-4' else location end)
) x(new_location)
group by t.date, x.new_location

Select values that meet both cases in A and B at the same time (WHERE condition)

I need to choose only number of people who are users of dbo.D_drug.ATC7_code LIKE 'A10B%' and dbo.D_drug.ATC7_code LIKE 'C10%' at the same time. So if patient didnt using both medication concurrently/together, he must be eliminated from the result.
Below is my demand, but i guess, its not correct. Thanks for help!.
SELECT DISTINCT dbo.drugconsumption.PatientDim AS ID_patient,
dbo.drug.code,
dbo.drug.description
FROM data_star.dbo.F_drugconsumption
LEFT JOIN dbo.D_drug ON DrugDim = dbo.D_drug.id
WHERE ( dbo.D_drug.ATC7_code LIKE 'A10B%'
OR
dbo.D_drug.ATC7_code LIKE 'C10%'
)
AND ( dbo.F_drugconsumption.DateDim >='20200101' )
AND ( dbo.F_drugconsumption.DateDim <='20201231' )
AND ( dbo.F_drugconsumption.AgeDim <='125' )
GROUP BY
dbo.F_drugconsumption.PatientDim,
dbo.D_drug.code,
dbo.D_drug.description
HAVING COUNT (dbo.D_drug.ATC7_code) = 2

SQL Server [PATSTAT] query | Multiple charindex values &

Hello Stack Overflow Community.
I am retrieving data with SQL from PATSTAT (patent data base from the European Patent Office). I have two issues (see below). For your info the PATSAT sql commands are quite limited.
I. Charindex with multiple values
I am looking for specific two specific patent groups ["Y02E" and "Y02C"] and want to retrieve data on these. I have found that using the charindex function works if I insert one group;
and charindex ('Y02E', cpc_class_symbol) > 0
But if I want to use another charindex function the query just times out;
and charindex ('Y02E', cpc_class_symbol) > 0 or charindex ('Y02C', cpc_class_symbol) >0
I am an absolute SQL rookie but would really appreciate your help!
II. List values from column in one cell with comma separation
Essentially I want to apply what I found as the "string_agg"-command, however, it does not work for this database. I have entries with a unique ID, which have multiple patent categories. For example:
appln_nr_epodoc | cpc_class_symbol
EP20110185794 | Y02E 10/125
EP20110185794 | Y02E 10/127
I would like to have it like this, however:
appln_nr_epodoc | cpc_class_symbol
EP20110185794 | Y02E 10/125, Y02E 10/127
Again, I am very new to sql, so any help is appreciated! Thank you!
I will also attach the full code here for transparency
SELECT a.appln_nr_epodoc, a.appln_nr_original, psn_name, person_ctry_code, person_name, person_address, appln_auth+appln_nr,
appln_filing_date, cpc_class_symbol
FROM
tls201_appln a
join tls207_pers_appln b on a.appln_id = b.appln_id
join tls206_person c on b.person_id = c.person_id
join tls801_country on c.person_ctry_code= tls801_country.ctry_code
join tls224_appln_cpc on a.appln_id = tls224_appln_cpc.appln_id
WHERE appln_auth = 'EP'
and appln_filing_year between 2005 and 2012
and eu_member = 'Y'
and granted = 'Y'
and psn_sector = 'company'
and charindex ('Y02E', cpc_class_symbol) > 0
For your part 2 here is a sample data i created
And here is the code. It gives me YOUR requested output.
create table #test_1 (
appln_nr_epodoc varchar(20) null
,cpc_class_symbol varchar(20) null
)
insert into #test_1 values
('EP20110185794','Y02E 10/125')
,('EP20110185794','Y02E 10/127')
,('EP20110185795','Y02E 10/130')
,('EP20110185796','Y02E 20/140')
,('EP20110185796','Y02E 21/142')
with CTE_1 as (select *
from (
select *
,R1_1 = Rank() over(partition by appln_nr_epodoc order by cpc_class_symbol )
from #test_1
) as a
where R1_1 = 1
)
,CTE_2 as (select *
from (
select *
,R1_1 = Rank() over(partition by appln_nr_epodoc order by cpc_class_symbol )
from #test_1
) as a
where R1_1 = 2 )
select a.appln_nr_epodoc
,a.cpc_class_symbol+','+c.cpc_class_symbol
from CTE_1 a
join CTE_2 c on c.appln_nr_epodoc = a.appln_nr_epodoc
Out put

Building/Creating SQL Metrics from the table

I have a table:
SELECT aaa.sr_nbr,
aaa.inst_nbr,
bb.country,
bb.sr_control_type,
bb.it_tran_code,
ccc.cust_name,
ccc.cust_nbr
FROM tablea1 aaa
INNER JOIN tablea2 bb
ON aaa.inst_id=bb.inst_id AND aaa.item_id=bb.item_id
LEFT JOIN table3 ccc
ON bb.inst_id=ccc.inst_id AND bb.item_id=ccc.item_id
WHERE ccc.cust_name NOT LIKE '%EXP%'
AND ccc.cust_name NOT LIKE '%RMAA%' mt;
Now, I have created, separately, queries for metrics, like:
SELECT mt.sr_nbr,
mt.inst_nbr,
mt.country,
mt.sr_control_type,
mt.it_tran_code,
mt.cust_name,
mt.cust_nbr
COUNT(mt.sr_nbr) as cnt_nbr
FROM mt
WHERE mt.it_tran_code <> 'D'
GROUP BY 1,2,3,4,5,6,7;
or the another one:
SELECT t_2.sr_nbr,
t_2.inst_nbr,
t_2.country,
t_2.sr_control_type,
t_2.it_tran_code,
t_2.cust_name,
t_2.cust_nbr
SUM(t_2.sn_dup) AS sn_dup_sum
FROM (
SELECT
t_1.sr_nbr,
t_1.inst_nbr,
t_1.country,
t_1.sr_control_type,
t_1.it_tran_code,
t_1.cust_name,
t_1.cust_nbr
COUNT(t_1.sr_nbr) AS sn_dup
FROM
(
SELECT
mt.sr_nbr,
mt.inst_nbr,
mt.country,
mt.sr_control_type,
mt.it_tran_code,
mt.cust_name,
mt.cust_nbr
FROM mt
WHERE ccc.cust_name NOT LIKE '%EXP%'
AND ccc.cust_name NOT LIKE '%RMAA%'
) AS t_1
GROUP BY 1,2,3,4,5,6,7
HAVING
COUNT(t_1.sr_nbr) > 1
) AS t_2
GROUP BY 1,2,3,4,5,6,7;
and so on... I have about 10 similar metrics.
Now, I do not know the best way how to "put" those query metrics within the main table/query.
You can insert results of a SELECT query into a table if you are able to fill the INSERT statement correctly.
Example:
INSERT INTO Customers (CustomerName, City, Country)
SELECT SupplierName, City, Country FROM Suppliers
WHERE Country='Germany';
Source: https://www.w3schools.com/sql/sql_insert_into_select.asp
Make sure the amount and types of the results matches the columns you're trying to insert.

Combining two nested SELECT with DISTINCT?

How do I look up DISTINCT values of one table, look for each name in another table and get both the values and their names as a result?
The Beleg table looks like this:
SELECT DISTINCT Ursprungskonto FROM Beleg
WHERE YEAR ( Valuta ) = 2016
gets me:
1000
1210
1220
1230
For each of these values, I need to lookup its name:
SELECT Name FROM Geldkonto
WHERE Kontonr = 1000
results in:
Kasse
At the end of the query, I need to have this result:
1000 Kasse
1210 OneBankName
1220 AnotherBankName
1230 YABN
I'm using SQL-92 (Filemaker).
Thanks a lot for any help!
You could try sub-query:
SELECT Kontonr , Name FROM Geldkonto
WHERE Kontonr in (SELECT DISTINCT Ursprungskonto FROM Beleg
WHERE YEAR ( Valuta ) = 2016)
You could use inner join
SELECT DISTINCT Beleg.Ursprungskonto, Geldkonto.Name
FROM Beleg
INNER JOIN Geldkonto
ON Beleg.Ursprungskonto=Geldkonto.Kontonr;
Instead of applying DISTINCT after the join you better do it before:
SELECT k.Kontonr, k.Name
FROM Geldkonto AS k
JOIN
(
SELECT DISTINCT Ursprungskonto
FROM Beleg
WHERE YEAR ( Valuta ) = 2016
) AS b
ON k.Kontonr = b.Ursprungskonto
This is similar to #rev_dihazum's solution, simply using a join instead of a subquery, useful if you need any additional columns from Beleg.