Find table with only two rows. Access 2016 - sql

I'm looking for a query that I can use in MS Access 2016 which will give me all Company ID's that have the values "Iphone" and "Ipad". So all CompanyID that has only two rows with specific values.
CompanyID Product_Name
1 Iphone
1 Ipad
1 Headphones
2 Iphone
2 Galaxy
3 Playstation 4
3 Nintendo Switch
4 Iphone
4 Ipad
In the example table above I will therefore get the CompanyID = 4.
I have tried to use the same logic as in SQL from the this post but Access doesn't allow syntax USING.
The SQL query used in post is:
SELECT CompanyID
FROM DATA AS a
JOIN DATA AS b
USING (CompanyID)
WHERE a.Product_Name = "Iphone"
AND b.Product_Name = "Ipad";
Any feedback is much appreciated.

Since you state:
So all CompanyID that has only two rows with specific values... In the
example table above I will therefore get the CompanyID = 4.
It would seem that you require the CompanyID for which the only two Product_Name values are Ipad & Iphone, with no other values associated with the CompanyID.
To obtain this result, I might suggest the following SQL query:
select t.companyid
from data t
group by t.companyid
having max(t.product_name in ('Iphone','Ipad'))=-1
Which will return:
CompanyID
4
Here, for every record within each group of records associated with a given CompanyID, the expression t.product_name in ('Iphone','Ipad') is evaluated.
This expression will either return True (-1) or False (0).
If all records within the group are either 'Iphone' or 'Ipad', then this expression will return True (-1) for every record, and the maximum over the group will be -1.
Whereas, if any record within the group is some other value, this expression will return False (0) and therefore the maximum of the group will be 0, thus excluding it from the result.

You can use an INNER JOIN to filter the results that do not contain both values:
SELECT a.CompanyID
FROM (
SELECT CompanyID
FROM DATA
WHERE Product_Name = 'IPhone'
) a
INNER JOIN (
SELECT CompanyID
FROM DATA
WHERE Product_Name = 'Ipad'
) b ON b.CompanyID = a.CompanyID
Output:
CompanyID
1
4
How does this work?
Firstly all results that have an IPhone are gathered. Then this is joined with all results that have an IPad. Only results with both rows matching (because of the INNER JOIN) will be returned.

While late to this, it looks like they're only being pulled from one table - DATA. If that's the case then the easiest solution should just be
SELECT DATA.CompanyID
FROM (DATA)
WHERE DATA.Product_Name = "Iphone"
AND DATA.Product_Name = "Ipad";
For Access, the FROM statement is generally only used for combining tables, or queries, and the data manipulation is in the other statements.
If there's more than one table and the connection between the two tables is CompanyID, then it should look more like this;
SELECT DATA1.CompanyID
FROM (DATA1 INNER JOIN DATA1.CompanyID ON DATA2.CompanyID)
WHERE DATA2.Product_Name = "Iphone"
AND DATA2.Product_Name = "Ipad";

Related

Display column which contains dynamic values based upon values in other tables

I have two tables: PROJECT_SELECTED and COMPANY
What I want to do is create a query which displays all COMPANIES along with a column that identifies whether or not that COMPANY has been selected for a project (which is in PROJECT_SELECTED) based upon a variable.
COMPANY
COMPANY_ID
COMPANY_NAME
1
Company1
2
Company2
3
Company3
PROJECT_SELECTED
This table shows whether a certain company has been selected for a specific project.
PROJECT_ID
COMPANY_ID
1
1
1
2
2
1
3
2
This is the output that I want
Variable: PROJECT_ID = 1
COMPANY_ID
PROJECT_TENDERED
1
True
2
True
3
False
The SQL I wrote out goes something like this:
SELECT CASE
WHEN COMPANY_ID EXISTS IN
(SELECT COMPANY_ID FROM PROJECT_SELECTED WHERE PROJECT_ID=1) THEN "TRUE"
ELSE "FALSE"
END AS PROJECT_TENDERED
FROM COMPANY;
The variable referenced above this table is what I will be using to determine which project I am referencing. I am not worried about the changing of variable as the program I am using (Microsoft Access/VBA) has a requery functionality.
Simply put, how do I make a column that does not exist in either table which defaults to no but yes if it is found in PROJECT_SELECTED. The important part is that I can see all companies.
Isn't it easier with LEFT JOIN?
SELECT
company.company_name,
IIF(project_selected.project_id IS NULL, 'False', 'True')
FROM
company
LEFT JOIN
project_selected
ON project_selected.company_id = company.company_id
AND project_selected.project_id = 1
Finally figured it out at my own peril.
Seems Access does not support CASE statements. We must use IIF instead. In the IIF expression I have an inner query which determines if the COMPANY_ID is in the PROJECT_SELECTED table for a certain project. This is achieved using the WHERE statement in the inner query.
I have figured out the query based upon this link
SELECT COMPANY_NAME,
IIF(COMPANY_ID IN
(SELECT COMPANY_ID FROM PROJECT_SELECTED WHERE PROJECT_ID = 1),'TRUE','FALSE')
AS PROJECT_TENDERED
FROM COMPANY;

SQL - compare multiple rows and return rows?

I have a large database and i'd like to pull info from a table (Term) where the Names are not linked to a PartyId for a certain SearchId. However:
There are multiple versions of the searches (sometimes 20-40 - otherwise I think SQL - Comparing two rows and two columns would work for me)
The PartyId will almost always be NULL for the first version for the search, and if the same Name for the same SearchId has a PartyId associated in a later version the NULL row should not appear in the results of the query.
I have 8 left joins to display the information requested - 3 of them are joined on the Term table
A very simplified sample of data is below
CASE statement? Join the table with itself for comparison? A temp table or do I just return the fields I'm joining on and/or want to display?
Providing sample data that yields no expected result is not as useful as providing data that gives an expected result..
When asking a question start with defining the problem in plain English. If you can't you don't understand your problem well enough yet. Then define the tables which are involved in the problem (including the columns) and sample data; the SQL you've tried, and what you're expected result is using the data in your sample. Without this minimum information we make many guesses and even with that information we may have to make assumptions; but without a minimum verifiable example showing illustrating your question, helping is problematic.
--End soap box
I'm guessing you're after only the names for a searchID which has a NULL partyID for the highest SearchVerID
So if we eliminated ID 6 from your example data, then 'Bob' would be returned
If we added ID 9 to your sample data for name 'Harry' with a searchID of 2 and a searchVerID of 3 and a null partyID then 'Harry' too would be returned...
If my understanding is correct, then perhaps...
WITH CTE AS (
SELECT Name, Row_Number() over (partition by Name order by SearchVersID Desc)
FROM Term
WHERE SearchID = 2)
SELECT Name
FROM CTE
WHERE RN = 1
and partyID is null;
This assigns a row number (RN) to each name starting at 1 and increasing by one for each entry; for searchID's of 2. The highest searchversion will always have a RN of 1. Then we filter to include only those RN which are 1 and have a null partyID. This would result in only those names having a searchID of 2 the highest search version and a NULL partyID
Ok So I took the question a different way too..
If you simply want all the names not linked to a PartyID for a given search.
SELECT A.*
FROM TERM A
WHERE NOT EXISTS (SELECT 1
FROM TERM B
WHERE A.Name = B.Name
AND SearchID = 2) and partyID is not null)
AND searchID = 2
The above should return all term records associated to searchID 2
that have a partyId. This last method is the exists not exists and set logic I was talking about in comments.

Dynamic SQL Case statement?

I have a table that is called DefaultCountries.
It contains the following columns:
CountryID INT
DefaultCountryID INT
CountryRank INT
I have 29 different countries with varying data for each country. For example:
CountryID of 1 has 2 records:
CountryID of 7 has 3 records
I have a table variable #CountryData that I'm trying to join to that currently has data for CountryIDs 1 and 10.
I would like to be able to match up to the DefaultCountryID found in the DefaultCountries table. So if I pass in CountryID = 1, I could do something like:
SELECT TOP 1 DefaultCountryID
WHERE CountryID = 1 -- that is my simple case.
Where I'm having an issue is where there are more than 2+ rows. As in my example for CountryID = 7. Basically I want to have something where if there is no records in my table that I'm trying to join to with the 1st record (CountryRank = 1) then I would like it to search for the next record.
So searching for CountryID = 7, then if nothing, then CountryID = 10 (so on and so forth).
I've tried different variations of this LEFT JOIN
SELECT *
FROM #CountryData cd
LEFT JOIN DefaultCountries dc ON dc.defaultCountryid = cd.CountryID
AND cd.CountryID = 7
But this just brings back all the data (1 & 10). Do I have to use a loop to do this the way I'm describing? I thought about a CASE statement as well, but since I could have more than 2+ in the DefaultCountries table I'm not sure how I could keep searching.
I tried doing an IN statement, but I have 2 issues there. I can't do an order by in the IN statement as I get the following message:
The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP, OFFSET
or FOR XML is also specified.
And even if there is a way to make sure I'm searching in the order I want using an IN statement, I want to make sure it stops searching on the 1st one it finds. So to expand on my example, if table (#CountryData) table now contains records where CountryID = 7 and CountryID = 10 I only want to return the records where CountryID = 7.
If i'm following you right you can just use a CTE
with cte as(
select
CountryID,
DefaulteCountryID,
ROW_NUMBER() over (partition by CountryID order by CountryRank) as rn
from DefaultCountries
where DefaultCountryID in (select distinct CountryID from #CountryData))
Then just join to this cte where rn = 1
So this would satisfy "Basically I want to have something where if there is no records in my table that I'm trying to join to with the 1st record (CountryRank = 1) then I would like it to search for the next record" meaning if there wasn't a 1 you'd get 2, or 3, or what ever the next order number is.

in sql how to return single row of data from more than one row in the same table

I have a single table of activities, some labelled 'Assessment' (type_id of 50) and some 'Counselling' (type_id of 9) with dates of the activities. I need to compare these dates to find how long people wait for counselling after assessment. The table contains rows for many people, and that is the primary key of 'id'. My problem is how to produce a result row with both the assessment details and the counselling details for the same person, so that I can compare the dates. I've tried joining the table to itself, and tried nested subqueries, I just can't fathom it. I'm using Access 2010 btw.
Please forgive my stupidity, but here's an example of joining the table to itself that doesn't work, producing nothing (not surprising):
Table looks like:
ID TYPE_ID ACTIVITY_DATE_TIME
----------------------------------
1 9 20130411
1 v 50 v 20130511
2 9 20130511
3 9 20130511
In the above the last two rows have only had assessment so I want to ignore them, and just work on the situation where there's both assessment and counselling 'type-id'
SELECT
civicrm_activity.id, civicrm_activity.type_id,
civicrm_activity.activity_date_time,
civicrm_activity_1.type_id,
civicrm_activity_1.activity_date_time
FROM
civicrm_activity INNER JOIN civicrm_activity AS civicrm_activity_1
ON civicrm_activity.id = civicrm_activity_1.id
WHERE
civicrm_activity.type_id=9
AND civicrm_activity_1.type_id=50;
I'm actually wondering whether this is in fact not possible to do with SQL? I hope it is possible? Thank you for your patience!
Sounds to me like you only want to get the ID numbers where you have a TYPE_ID entry of both 9 and 50.
SELECT DISTINCT id FROM civicrm_activity WHERE type_id = '9' AND id IN (SELECT id FROM civicrm_activity WHERE type_id = '50');
This will give you a list of id's that has entries with both type_id 9 and 50. With that list you can now go and get the specifics.
Use this SQL for the time of type_id 9
SELECT activity_date_time FROM civicrm_activity WHERE id = 'id_from_last_sql' AND type_id = '9'
Use this SQL for the time of type_id 50
SELECT activity_date_time FROM civicrm_activity WHERE id = 'id_from_last_sql' AND type_id = '50'
Your query looks OK to me, too. The one problem might be that you use only one table alias. I don't know, but perhaps Access treats the table name "specially" such that, in effect, the WHERE clause says
WHERE
civicrm_activity.type_id=9
AND civicrm_activity.type_id=50;
That would certainly explain zero rows returned!
To fix that, use an alias for each table. I suggest shorter ones,
SELECT A.id, A.type_id, A.activity_date_time,
B.type_id, B.activity_date_time
FROM civicrm_activity as A
JOIN civicrm_activity as B
ON A.id = B.id
WHERE A.type_id=9
AND B.type_id=50;

How to get one common value from Database using UNION

2 records in above image are from Db, in above table Constraint are (SID and LINE_ITEM_ID),
SID and LINE_ITEM_ID both column are used to find a unique record.
My issues :
I am looking for a query it should fetch the recored from DB depending on conditions
if i search for PART_NUMBER = 'PAU43-IMB-P6'
1. it should fetch one record from DB if search for PART_NUMBER = 'PAU43-IMB-P6', no mater to which SID that item belong to if there is only one recored either under SID =1 or SID = 2.
2. it should fetch one record which is under SID = 2 only, from DB on search for PART_NUMBER = 'PAU43-IMB-P6', if there are 2 items one in SID=1 and other in SID=2.
i am looking for a query which will search for a given part_number depending on Both SID 1 and 2, and it should return value under SID =2 and it can return value under SID=1 only if the there are no records under SID=2 (query has to withstand a load of Million record search).
Thank you
Select *
from Table
where SID||LINE_ITEM_ID = (
select Max(SID)||Max(LINE_ITEM_ID)
from table
where PART_NUMBER = 'PAU43-IMB-P6'
);
If I understand correctly, for each considered LINE_ITEM_ID you want to return only the one with the largest value for SID. This is a common requirement and, as with most things in SQL, can be written in many different ways; the best performing will depend on many factors, not least of which is the SQL product you are using.
Here's one possible approach:
SELECT DISTINCT * -- use a column list
FROM YourTable AS T1
INNER JOIN (
SELECT T2.LINE_ITEM_ID,
MAX(T2.SID) AS max_SID
FROM YourTable AS T2
GROUP
BY T2.LINE_ITEM_ID
) AS DT1 (LINE_ITEM_ID, max_SID)
ON T1.LINE_ITEM_ID = DT1.LINE_ITEM_ID
AND T1.SID = DT1.max_SID;
That said, I don't recall seeing one that relies on the UNION relational operator. You could easily rewrite the above using the INTERSECT relational operator but it would be more verbose.
Well in my case it worked something like this:
select LINE_ITEM_ID,SID,price_1,part_number from (
(select LINE_ITEM_ID,SID,price_1,part_number from Table where SID = 2)
UNION
(select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 1 and line_item_id NOT IN (select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 2)))
This query solved my issue..........