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

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;

Related

SQL: At least one value exists in another table

I am trying to create a table that has columns called user_id and top5_foods (binary column). I currently have two tables, one has all of the user_ids and the foods associated with those user_ids and one table that only contains the top5 foods according to a type of calculation to select the top5 foods.
The table that I am trying to create if to have the column of the user_id and if at least one of their favorite foods is in the top_5_food table, put the value of the top5_foods as 1 and if not, 0.
Something like the following:
user_id top5_foods
----------------------
34223 1
43225 0
34323 1
I have tried to use the CASE command but it just duplicated the user_ids and mark 1 or 0 whenever it finds a food that is in the top_5_foods table. But I don't want it to duplicate. Could you please help ?
Thank you very much
If I understand correctly, a left join and aggregation:
select uf.user_id,
(count(t.food_id) > 0) as top5_foods
from user_foods uf left join
top5_foods t
on uf.food_id = t.food_id
group by uf.user_id;

Find table with only two rows. Access 2016

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";

How can I have UNION respect column aliases?

Sorry for the bad title, I couldn't think of anything better. Feel free to edit.
I have to work with a db table that uses one column to store different types of information (last name if person, company name if company). A nightmare, I know, but it's what it is.
To distinguish the meaning, there is another column with an integer that specifies the type of what's in the name column.
The schema of this table looks as follows (simplified):
ID int
dtype int
name varchar(50)
So, a sample could look like this:
ID dtype name
---------------------------
1 0 Smith
2 0 Trump
3 1 ABC Ltd.
4 1 XYZ Ltd.
I'm trying to normalize this using the following T-SQL code:
WITH companies AS
(
SELECT ID, name AS company
FROM nametable WHERE dtype=1
),
people AS
(
SELECT ID, name AS person
FROM nametable WHERE dtype=0
),
SELECT * FROM companies UNION ALL SELECT * FROM people;
What I hoped to get is a new table with the schema:
ID
dtype
company
person
Or, in table view:
ID dtype person company
------------------------------------------
1 0 Smith
2 0 Trump
3 1 ABC Ltd.
4 1 XYZ Ltd.
Instead, the field is now just called person instead of name but it's still just one field for 2 types of information.
I understand I could just create a new table and insert each partial result into it but it seems there should be a simpler way. Any advice appreciated.
It seems you need case when which helps you
select ID, dtype,case when dtype=0 then name end AS company,
case when dtype=1 then name end AS person
FROM nametable
The CASE statement goes through conditions and return a value when condition is met, from your sample input and output its clear you want to create type wise new column ,so i used case Statement
You don't need to use UNION for this at all. A better approach would be using a bit of aggregation.
SELECT ID,
MAX(CASE WHEN dtype = 0 THEN [name] END) AS company
MAX(CASE WHEN dtype = 1 THEN [name] END) AS person
FROM nametable
GROUP BY ID;
UNION (ALL) doesn't "care" for aliases though. It combines the datasets it receives into 1. All the datasets must have the same definition and the dataset returned will have the same definition. If the datasets have different aliases for columns, the aliases supplied in the first dataset will be used. UNION doesn't detect that the datasets have different names for the columns and therefore return the different names as different columns; that's not what a UNION does.
Edit: well this will give the OP the data they want, however, there's no need for the aggregation. I was honestly expected ID's to be a shared resource; because that's normally the only time you have such horrid tables. The fact that it isn't just makes this table even more confused...

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..........

SQL Precedence Query

I have a logging table which has three columns. One column is a unique identifier, One Column is called "Name" and the other is "Status".
Values in the Name column can repeat so that you might see Name "Joe" in multiple rows. Name "Joe" might have a row with a status "open", another row with a status "closed", another with "waiting" and maybe one for "hold". I would like to, using a defined precedence in this highest to lowest order:("Closed","Hold","Waiting" and "Open") pull the highest ranking row for each Name and ignore the others. Anyone know a simple way to do this?
BTW, not every Name will have all status representations, so "Joe" might only have a row for "waiting" and "hold", or maybe just "waiting".
I would create a second table named something like "Status_Precedence", with rows like:
Status | Order
---------------
Closed | 1
Hold | 2
Waiting | 3
Open | 4
In your query of the other table, do a join to this table (on Status_Precedence.Status) and then you can ORDER BY Status_Precedence.Order.
If you don't want to create another table, you can assign numeric precedence using a SELECT CASE
Select Name, Status, Case Status
When 'Closed' then 1
When 'Hold' then 2
When 'Waiting' then 3
When 'Open' Then 4
END
as StatusID
From Logging
Order By StatusId -- Order based on Case
A lookup table is also a good solution though.
I ended up using matt b's solution and using this final query to filter out the lower ranked (lower bing higher numbered).
SELECT * from [TABLE] tb
LEFT JOIN Status_Precedence sp ON tb.Status = sp.Status
WHERE sp.Rank = (SELECT MIN(sp2.rank)
FROM[Table] tb2
LEFT JOIN Status_Precedence sp2 ON tb2.Status = sp2.Status
WHERE tb.Status = tb2.Status)
order by tb.[name]