Access VBA: Select only multiple values - sql

Say, I have a table that looks like this:
ID | PNo | MM | CP |
---|-----|------|----|
1 | 13 | True | 4 |
2 | 92 | True | 3 |
3 | 1 | True | 3 |
4 | 13 | False| 2 |
5 | 13 | True | 3 |
6 | 1 | True | 3 |
I want to go through all PNos and compare all rows with that PNo and only select those that have different values in field MM.
My plan was to create a table with the distinct values of PNo, iterate through that table by using the usual record set and write an SQL query for each PNo.
Now my problem is the construction of the SQL query.
I can select all rows with Table.PNo = rs("PNo") but I have no idea how to formulate the query to catch the rows with varying values.

You can use a subquery:
Select *
From YourTable
Where PNo IN
(Select T.PNo
From YourTable
Group By PNo, MM
Having Count(*) = 2)

I think this should work.
This will create a cartesian product on y our PNo field. i.e. Every record connected to every record (but just on that PNo).
SELECT *
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.PNo = T2.PNo
You'll end up with 9 instances of PNo 13, 4 of 1 and 1 of 92. Now we just want to return the ones where MM is different, so add that to the WHERE clause.
SELECT *
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.PNo = T2.PNo
WHERE T1.MM <> T2.MM
ORDER BY T1.ID
This will return four records. PNo 1 and 92 will have vanished as the MM result was the same for those. ID number 4 will be returned twice as the MM value is different from that in ID 1 and ID 5.
To remove the duplicate value you could then use DISTINCT:
SELECT DISTINCT T1.ID, T1.PNo, T1.MM, T1.CP
FROM Table1 T1 INNER JOIN Table1 T2 ON T1.PNo = T2.PNo
WHERE T1.MM <> T2.MM
ORDER BY T1.ID
Note: One of the differences between the answer given by #Jonathan and mine is that his query is updateable and mine isn't.

The following should do what you want:
SELECT * FROM MyTable WHERE PNo in
(SELECT t.PNo FROM MyTable t
INNER join MyTable f
ON t.PNo = f.PNo
WHERE t.MM = true and f.MM = false)
The inner join ensures that only those PNos that have both MM false and MM true are included.

Related

SQL - How to pick the best available value for each column for each ID from multiple tables?

I have two tables with the same variables referring to attributes of a person.
How can I combine data from two such tables picking the best available value for each column from each table for each field?
Requirements:
For each field, I would like to fill it with a value from either one of the tables, giving a preference to table 1.
Values can be NULL in either table
In the combined table, the value for column 1 could come from table 2 (in case table 1 is missing a value for that person) and the value for column 2 could from table 1 (because both tables had a value, but the value from table 1 is preferred).
In my real example, I have many columns, so an elegant solution with less code duplication would be preferred.
Some users may exist in only one of the tables.
Example:
Table 1:
user_id | age | income
1 | NULL| 58000
2 | 22 | 60000
4 | 19 | 35000
Table 2:
user_id | age | income
1 | 55 | 55000
2 | 19 | NULL
3 | 22 | 33200
Desired output:
user_id | age | income
1 | 55 | 58000
2 | 22 | 60000
3 | 22 | 33200
4 | 19 | 35000
I think that's a full join and priorization logic with colaesce():
select user_id,
coalesce(t1.age, t2.age) as age,
coalesce(t1.income, t2.income) as income
from table1 t1
full join table2 t2 using(user_id)
Use full outer join if user_id in each table is unique.
SELECT
COALESCE(t1.user_id, t2.user_id) AS user_id,
GREATEST(t1.age, t2.age) AS age,
GREATEST(t1.income, t2.income) AS income
FROM t1
FULL OUTER JOIN t2 ON t1.user_id = t2.user_id
try like below using coalesce()
select t1.user_id, coalesce(t1.age,t2.age),
t1.income>t2.income then t1.income else t2.income end as income
table1 t1 join table2 t2 on t1.usesr_id=t2.user_id
You can use below code:
With TableA(Id,age,income) as
( --Select Common Data
select table_1.id,
--Select MAX AGE
case
when table_1.age> table_2.age or table_2.age is null then table_1.age else table_2.age
end,
--Select MAX Income
case
when table_1.income>table_2.income or table_2.income is null then table_1.income else table_2.income
end
from table_1 inner join table_2 on table_2.id=table_1.id
union all
-- Select Specific Data of Table 2
select table_2.id,table_2.age,table_2.income
from table_2
where table_2.id not in (select table_1.id from table_1)
union all
-- Select Specific Data of Table 1
select table_1.id,table_1.age,table_1.income
from table_1
where table_1.id not in (select table_2.id from table_2)
)select * from TableA

How to create a calculated column in access that is based in a conditional sum of another table

It is possible in MS ACCESS 2016 to create a column in a table that is a conditional SUM of another table?
Example
Table 1 - Columns
ID, NAME, TOTAL
Table 2 - Columns
ID, NAME, IDREF, CUSTO
Data:
Table 1
ID | Name | Total
---+-------+----------------------------------------------------------------
35 | Test | "SUM(CUSTO) of ALL ELEMENTS OF TABLE 2 WHERE table2.IDREF = table1.ID"
Table 2
ID | Name | IDREF | CUSTO
---+-------+-------+--------
1 | Test | 35 | 50
2 | Test | 35 | 30
3 | abcd | 12 | 30
4 | Test | 35 | 10
The result should be:
table 1
ID | Name | Total
---+------+------
35 | Test | 90 (50 + 30 + 10 from table 2 where idref = 35)
You can use a subquery:
select t1.*,
(select sum(t2.CUSTO)
from table2 as t2
where t2.idref = t1.id
) as total
from table1 as t1;
More efficiently, consider an aggregate subquery in JOIN to run only once and not SELECT subquery that runs for every row.
SELECT t1.*, agg.Total
FROM table1 as t1
INNER JOIN
( SELECT t2.idref, SUM(t2.CUSTO) AS Total
FROM table2 as t2
GROUP BY t2.idref
) AS agg
ON agg.idref = t1.id
Alternatively, replace subquery with exact saved query for even more efficiency per Allen Browne's optimizing query tips in MS Access:
A subquery will be considerably faster than a domain aggregate function. In most cases, a stacked query will be faster yet (i.e. another saved query that you include as a "table" in this query.)
SELECT t1.*, q.Total
FROM table1 as t1
INNER JOIN mySavedAggQuery q
ON q.idref = t1.id

SQL dividing column by a number in another table

I have two tables:
total_table =
| Title | Value |
|-------|-------|
| total | 20 |
breakdown_table =
| Title | Value |
|--------|-------|
| total | 20 | (this is the same as the above table)
| type a | 10 |
| type b | 5 |
| type c | 5 |
I would like to create a new table which includes both columns from breakdown_table but adds a 3rd column that shows the breakdown percentages (100%, 50%, 25%, 25%). How can I do this without hardcoding the denominator?
Here's some syntax I've tried but it keeps giving me errors about commas and equijoin. I'm not trying to join the tables with a key, I just want to use the single value in the total_table.
data_out = SELECT breakdown_table.*,
breakdown_table.Value / total.Value
FROM breakdown_table, total_table;
You can cross join the tables (properly):
SELECT
b.*,
100.0 * b.Value / t.Value as data_out
FROM breakdown as b cross join total as t;
You can try using cross join:
select t1.Title, t1.Value, 100 * t1.Value / t2.Value AS BPCT
from mytable t1
cross join mytable t2
where t2.Title = "total"
Very similar to other answers here but will get you the percentages in the right format.
select t1.*, format(t1.value/1.0/t2.value,'P0') as pcnt
from breakdown_table t1 cross apply total_table t2
If you wish to use the implicit join method, then you need to change the column name in total_table
select t1.*,format(value*1.0/total,'P0') as pcnt
from breakdown_table t1,(select value as total from total_table) t2

Retrieve data from the same table if subId is an id of other item

I have a table that contains some records, and I would like to get only these records that have subID to a record with the id of the subID value. If there is no row with the id then do not take this row to the table. Also do not duplicate values if already in the table and do not look at rows that have subId 0 because they are as parents we can say so they do not have childs
----------------------------
ID | SUBID | NAME | ENABLED |
30 | 0 | EXP1 | TRUE |
55 | 30 | EXP2 | TRUE |
70 | 30 | EXP3 | FALSE |
99 | 42 | EXP4 | FALSE |
232| 0 | EXP5 | TRUE |
65 | 232 | EXP6 | TRUE |
-----------------------------
Expected result:
----------------------------
ID | SUBID | NAME | ENABLED |
30 | 0 | EXP1 | TRUE |
55 | 30 | EXP2 | TRUE |
70 | 30 | EXP3 | FALSE |
232| 0 | EXP5 | TRUE |
65 | 232 | EXP6 | TRUE |
-----------------------------
If someone could help me how to write this SQL statement in a good way I will be grateful.
You can use 'Exists':
SELECT T1.* FROM TEST T1
WHERE EXISTS (SELECT T2.ID FROM TEST T2 WHERE T2.ID = T1.SUBID)
OR EXISTS (SELECT T3.SUBID FROM TEST T3 WHERE T3.SUBID = T1.ID)
Test Result:
DB<>Fiddle
How about a union
select a.*
from have a
inner join have b
on a.subid=b.id
union
select b.*
from have a
inner join have b
on a.subid=b.id;
This can be actually pretty complicated, as you've evidently found out. I'd suggest a CTE and a UNION with your JOINs and aliases. It also looks like it'll need all that in a subquery to do a DISTINCT, too.
Without testing this, I'd image it looks something like this:
WITH MAIN AS (
SELECT ID, SUBID, NAME
FROM TABLE t
WHERE ENABLED = TRUE
)
SELECT DISTINCT ID, NAME
FROM (
SELECT ID, NAME
FROM MAIN
UNION
SELECT t.ID, t.NAME
FROM MAIN
LEFT JOIN TABLE t on MAIN.SUBID = t.ID
WHERE MAIN.SUBID <> 0
)
The outer select might not be needed if you do a distinct on each of the inner queries, but without testing it, I can't say for sure. I'd guess it would only DISTINCT the two lists separately, which isn't your intended result.
I'm kind of hoping someone else can come up with a less complicated version. I'd also suggest you do some more research on CTEs, UNIONs, aliases, and see if you can make this simpler on your own. But this should get you in the right direction.
BTW, I used a CTE (WITH MAIN AS) so that the query wouldn't be duplicated.
Try this script-
SELECT YT.*
FROM your_table YT
INNER JOIN (
SELECT DISTINCT(B.ID)
FROM your_table A
LEFT JOIN your_table B
ON A.SUBID = B.ID
WHERE B.ID IS NOT NULL
) C ON YT.ID = C.ID OR YT.SUBID = C.ID
By my understanding of what you are trying to do, you simply want:
SELECT * FROM myTable t1
WHERE SubID = 0
OR EXISTS (SELECT NULL FROM myTable t2 WHERE t2.id = t1.SubID)

SELECT query with cross rows WHERE statement

I'll try to explain the type of the query that I want:
Assume I have a table like this:
| ID | someID | Number |
|----|--------|--------|
| 1 | 1 | 10 |
| 2 | 1 | 11 |
| 3 | 1 | 14 |
| 4 | 2 | 10 |
| 5 | 2 | 13 |
Now, I want to find the someID that have a specific numbers (For example query for numbers 10, 11, 14 will return someID 1 and query for numbers 10, 13 will return 2). But, if someID contains all the query numbers but also more numbers, it will not return by the query. (For example query for 10, 11 will return nothing).
Is it possible?
SELECT t1.someId
FROM yourTable t1
WHERE t1.number IN (10,14,11)
GROUP BY t1.someID
HAVING COUNT(DISTINCT t1.ID) = (SELECT COUNT(DISTINCT t2.ID) FROM yourTable t2 WHERE t1.someID=t2.someID)
Example Fiddle
select someID
from yourtable
where number in (10,11,14)
and not exists (select * from yourtable t2 where number not in(10,11,14)
and t2.someid=yourtable.someid)
group by someID
having count(distinct ID) = 3
Where 3 is the number of items you are querying for
Yes, once you get the query numbers into a table variable (say it's called #QNums, with one column named QNum)) try
Select distinct someId
From table t
Where exists (Select * from #QNums
where QNum = t.Number)
And not Exists (Select * From table t2
Where someId = t.someId
And not exists(Select * From #QNums
where QNum = t3.Number))