MS Access Subquery that returns Multiple Fields - sql

So im back again with more MS Access problems. I have a INSERT INTO query with a subquery that checks to see if the data already exists.
SELECT name, course
FROM foo
WHERE (name, course) NOT IN (SELECT name, course FROM bar);
to expound a little on what i am trying to accomplish since the above doesn't work.
I am trying to select composite keys that do not exist already in the table bar. For example the following could be stored in the table bar:
"John Doe" , "Calc 101"
"John Doe" , "English"
"Jane Doe" , "Calc 101"
And the following could be in the table foo:
"John Doe", "Calc 101"
"John Doe", "Science"
The query should return the following:
"John Doe", "Science"
Everywhere i have looked says the above will work and im sure it does in theory. The problem i run into is with MS Access... When i attempt to run this query it pops up stating that the subquery will return multiple fields. Indeed it should as that is what i want it do do is return 2 fields that i can compare the other 2 fields. The above 2 fields are a composite key in my "bar" database.
For more background I am using MS Excel 2007 and MS Access 2007. The Excel is being used to input data and running the query through VB script. I am trying to make a subquery that checks for fields already in the final database because i ran into the error of MS Access opening up and spitting out a ERROR message about appending primary keys and closes with out executing the query. <-- That is to be expected due to the composite key.

Use LEFT JOIN and look for NULL values:
SELECT bar.name, bar.course
FROM bar LEFT JOIN foo ON bar.name = foo.name AND bar.course = foo.course
WHERE foo.name IS NULL
I've updated the SQLFiddle to include the INSERT followed by a SELECT to show the final table. I've also added composite primary keys to both tables so you can see that you do not get any duplicate inserts.

your sub query is returning two columns. make it return one. If want a where clause that can be in two columns, use OR
SELECT name, course
FROM foo
WHERE (name) NOT IN (SELECT name FROM bar) and (course)
NOT IN (SELECT course FROM bar);
Edit:
Your problem stems from a normalization issue. A suggested redesign would be to have a table for students and a table for courses and a table to join them. Example:
**StudentTable**
studentId(int PK)
firtName(string)
lastName(string)
**ClassTable**
classId(int PK)
ClassName
ClassDesc
**classTable_studentTable**
studentClassID
studentID
classID
Each student can have many classes and each class can have many students. It's a many to many relationship that is normalized by using the join table.
Now, if you wanted to do a query like your asking:
Select *.student, *.class
from
studentTable as student,
classTable as class
where
student.name<>'allen' and class.name<>'math'

Related

PHP/ Laravel application- query two database tables that are related through a third table? Inner join

I'm working on a Laravel/ Angular application, and have a form on one of pages displaying a table with information regarding a number of accounts. One of the columns in the table is titled 'Contact', and each cell in the column displays the name of the default contact for that table entry.
The cells in this column also display an 'Edit' button, which will open a dialog when clicked to allow the user to add another contact to that table entry- the dialog displays a form with the fields 'first name' 'surname' & 'email', and has an 'Add Contact' button.
There is also a short 'preview' of how the name should appear displayed in a letter generated to send to that user, i.e "Hi forename surname" or "Hi forename", depending on the the type of contact, and the letter template being used.
I'm having a bit of trouble getting the relevant name to be displayed, because I'm not sure how to write the SQL query I'll need to retrieve the relevant name.
The tables are set up such that the account.account table contains the values for:
'account ID', 'account name', account type ID',
and the account.property table contains the values for
'property ID', property label', 'property tag', 'property description'.
In the account.property table, there are two rows which hold the names to be used for different methods of communication- one with the 'property tag' addresseename, and the other with the 'property tag' addresseenamepdf. I want to display these values in the 'preview' on the dialog, but I'm not sure how to write the SQL to retrieve them.
As far as I can see, there is no primary/ foreign key relationship between the tables, but I have been told that they are linked using the View account.vAccount. It's been several years since I've done anything more than very basic database programming with SQL, and I haven't come across views before, so am unsure how to use them in a query...
In MS SQL SMS, if I right-click the `account.vAccount view, and select the top 1000 rows, I see that the query:
SELECT TOP (1000) [accountId]
,[name]
,[typeId]
,[accountType]
,[accountTypeTag]
,[typeParentId]
,[parentAccountType]
,[parentAccountTypeName]
,[balanceDate]
, // several other values here
FROM [myDB].[account].[vAccount]
is run, and am presented with a list of the results, which I can filter by adding a where clause to the end of the query:
FROM [myDB].[account].[vAccount] where accountId = 53092;
and this just returns the view row for that particular account. However, I can't see the addresseename & addresseenamepdf columns whose data I want to retrieve from the account.property table.
My (limited) understanding of SQL tells me that I will need to create a relationship between these two tables, in order to be able to query the addressename & addresseenamepdf values that I want using just the accountId value (i.e. have a foreign key from one of the tables in the other table).
Is my understanding correct here, or can I use the view to retrieve this data without creating a relationship between the tables? If I can, how would I do this?
--Edit--
So it seems I'd missed that these two tables are actually related through a third table (I've only just started working on this application)- the tables are:
account
accountID (PK)
name
typeId
...
propertyValue
propertyValueId (PK)
accountId
propertyId
...
property
propertyId (PK)
propertyLabel
propertyTag
...
The tables have the relationships:
account one-to-many propertyValue many-to-one property
How would I write a query that would return two particular properties (the properties whose propertyId values are 48 & 49 for an account where the accountId value is 53092?
I've tried running the query:
SELECT TOP (1000) [accountID]
,[name
...
FROM [myDB][account].[account] where accountID = 53092
INNER JOIN [myDB].[account].[propertyValue] where propertyTag = 'ADDRESSEENAME' | propertyTag = 'ADDRESSEENAMEPDF';
but when I try to execute, I get an error that says:
Incorrect syntax near the keyword 'INNER'.
Why am I getting this? What am I doing wrong?
Structure of the query should be
Select
From
join on
where
group by
Having.
You have the where clause, before the join clause.
Change to:
SELECT TOP (1000) [accountID]
,[name
...
FROM [myDB][account].[account]
INNER JOIN [myDB].[account].[propertyValue] ON … (you are missing the on clause)
where accountID = 53092 and (
propertyTag = 'ADDRESSEENAME' | propertyTag = 'ADDRESSEENAMEPDF');

Is there a way to select automatically the row pointed by an FK on a given table?

Today while writing one of the many queries that every developer in my company write every day I stumbled upon a question.
The DBMS we are using is Sql Server 2008
Say for example I write a query like this in the usual PERSON - DEPARTMENT db example
select * from person where id = '01'
And this query returns one row:
id name fk_department
01 Joe dp_01
The question is: is there a way (maybe using an addon) to make sql server write and execute a select like this
select * from department where id = 'dp_01'
only by for example clicking with the mouse on the cell containing the fk value (dp_01 in the example query)? Or by right click and selecting something like ("Go to pointed value")?
I hope I didn't wrote something stupid or impossible by definition
Not really, but that seems like a silly thing to do. Why would you want to confuse an id with a department name?
Instead, you could arrange things so you could do:
select p.*
from person p
where department = 'dp_01';
You would do this by adding a computed column department that references a scalar function that looks up the value in the department table. You can read about computed columns here.
However, a computed column would have bad performance characteristics. In particular, it would basically require a full table scan on the person table, even if that is not appropriate.
Another solution is to create a view, v_person that has the additional columns you want. Then you would do:
select p.*
from v_person p
where department = 'dp_01';
Why can't you write yourself by saying
select * from department where id =
(select fk_department from person where id = '01')

SQL Cross-Table Referencing

Okay, so I've got two tables. One table (table 1) contains a column Books_Owned_ID which stores a series of numbers in the form of 1,3,7. I have another table (table 2) which stores the Book names in one column and the book ID in another column.
What I want to do is create an SQL code which will take the numbers from Books_Owned_IDand display the names of those books in a new column. Like so:
|New Column |
Book 1 Name
Book 2 Name
Book 3 Name
I can't wrap my head around this, it's simple enough but all the threads I look on get really confusing.
Table1 contains the following columns:
|First_Name| Last_Name| Books_Owned_ID |
Table2 contains the following columns:
|Book_Name|Book_ID|
You need to do an inner join. This is a great example/reference for these
SELECT Book_Name FROM Table2
INNER JOIN Table1
ON Table1.Books_Owned_ID = Table2.Book_ID
EDIT SQL Fiddle
I will work on getting the column comma split working. It wont be a lot extra for this.
EDIT 2 See this answer to build a function to split your string. Then you can do this:
SELECT Book_Name FROM Table2
WHERE Book_ID IN(SELECT FN_ListToTable(',',Table1.Books_Owned_ID) FROM Table1 s)
The core of this centers around data normalisation... Each fact is stored only once (and so is "authoritative"). You should also get into the habit of only storing a single fact in any field.
So, imagine the following table layouts...
Books
Id, Name, Description
Users
Id, Username, EmailAddress, PasswordHash, etc....
BooksOwned
UserId, BookId
So if a single user owns multiple books, there will be multiple entries in the BooksOwned table...
UserId, BookID
1, 1
1, 2
1, 3
Indicates that User 1 owns books 1 through 3.
The reason to do it this way is that it makes it much easier to query in future. You also treat BookId as an Integer instead of a string containing a list - so you don't need to worry about string manipulation to do your query.
The following would return the name of all books owned by the user with Id = 1
SELECT Books.Name
FROM BooksOwned
INNER JOIN Books
ON BooksOwned.BookId = Books.Id
WHERE BooksOwned.UserId = 1
You need a function which takes a comma separated list and returns a table. This is slow and fundamentally a bad idea. Really all this does is convert this way of doing it to be like the data model I describe below. (see ProfessionalAmateur's answer for an example of this).
If you are just starting change your data model. Make a linking table. Like this:
Okay, so I've got two tables. One table (table 1) contains a column Books_Owned_ID which stores a series of numbers in the form of 1,3,7. I have another table (table 2) which stores the Book names in one column and the book ID in another column.
What I want to do is create an SQL code which will take the numbers from Books_Owned_IDand display the names of those books in a new column. Like so:
Person Table
|First_Name| Last_Name| Person_ID |
Book Table
|Book_Name|Book_ID|
PersonBook Table
|PersonID|BookID|
This table can have more than one row for each person.

MS Access - Linking to record through stored ID

I have a few tables set up in Access as follows (forgive the slightly redundant example content):
Table 1:
- ID
- FirstName
- SecondName
Table 2:
- ID
- Details
- PersonID -> Table 1[ID]
Table 3:
- ID
- Group
- PersonDetails -> Table 2[ID]
Table 1 is the base table containing records and retrieving no other information. For example, it could store someone's first and second names, along with an autonumber ID.
Table 2 contains records which, amongst other things, contain a field that links to Table 1 and stores the ID of one of the records held there. With the lookup wizard I can choose to utilise all fields from Table 1, store the ID of the Table 1 record in the Table 2 field and also display the first and second names in the combobox on the form to make choosing a record more intuitive.
In table 3, I need to store the ID of one of the records in Table 2. However, I would also like to again display in the form combobox the first and second names from the related record (in Table 1) whose ID is stored in Table 2. I can't choose to utilise, for example, the PersonDetails field from table 2 as this just puts ID numbers into the combobox - I'd need to do something equivalent of:
Table 2[ID]->[FirstName]
Is this possible to do with the lookup wizard in Access or would I have to look into queries or VBA?
Thanks.
Your query for your combo should look something like this:
SELECT cp.ID, cp.ReferenceName, c.Company, p.FeePerHour
FROM (ClientProfile AS cp LEFT JOIN Clients AS c ON cp.ClientID = c.ID)
LEFT JOIN Pricing AS p ON cp.PricePlanID = p.ID;
The main problem with your query is that you're missing the Parenthesis that are needed when you have multiple joins. If you had another join, you'd need a second set of parenthesis.
I took some liberty and used table aliases. It makes SQL concise and more readable.
If this query still doesn't work it might be because you're trying to join "child tables" to the "main table" without using your Foreign Key fields as the joining field. If this were my database the SQL would look something like this:
SELECT cp.ClientProfileID, cp.ReferenceName, c.Company, p.FeePerHour
FROM (ClientProfile AS cp LEFT JOIN Clients as C ON cp.ClientID = c.ClientID)
LEFT JOIN Pricing AS p ON cp.ClientProfileID = p.ClientProfileID;
Personally, I basically never use just plain ID as a field name. And when creating a foreign key I usually use the same field name as what the original table has. There are exceptions, especially in the case where you need to link back to the same table more than once. Consider the case where you are tracking real estate properties and you have a Buyer and a Seller that are both entities (but different from each other) in the same People table. You would then need to name them something like BuyerID and SellerID but ultimately they would link back to the PersonID in the Person table.
So Here's the table design I would go for. Notice I changed Group to PriceGroup. Watch out for reserved words when programming, not only in SQL but any language. If you name your field Group at some point you'll be trying to "Group on Group" which sounds and looks bad, if nothing else.
Client:
- ClientID
- FirstName
- SecondName
ClientProfile:
- ClientProfileID
- Details
- ClientID (Foreign Key to Client)
Pricing:
- PricingID
- PriceGroup
- ClientProfileID (Foreign Key to ClientProfile)

sql query with "with and in clause"

i have a table which store user name, hobby and city .hobby field contain different hobby joined using "," operator eg swimming, basket, cricket. I want to search user name who match at least one hobby according to my search criteria.
You should not have multiple attributes in one column. That's one of the number one rules of 3nf database design. Now you have to figure out ways to parse this data. This issue only gets worse and worse each and every day. Seperate the hobbies as multiple rows in your database.
I agree with #JonH that there shouldn't be more than one piece of information in a column. It stops the row being truly atomic.
But you are where you are, and you can use the LIKE clause to return rows that match a substring within a column.
Something like:
select hobbycolumn from hobbytable where hobbycolumn like '%swimming%'
for example
To do this properly you need to restructure your tables if possible. For what you are looking for a possible way would be to have 3 tables. I'm not sure who the city belongs to, so I put it with the user.
1 for user with the following cols:
id
name
city
A table for for hobbies:
id
name
And a user_hobbies join table that allows each user to have multiple hobbies, and each hobby to have multiple users:
id
user_id (foreign key)
hobby_id (foreign key)
Then searching for a user with a certain hobby is:
SELECT user.id, user.name FROM user
INNER JOIN 'user_hobbies' on user_hobbies.user_id=user.id
INNER JOIN 'hobbies' on hobbies.id = user_hobbies.hobby_id
WHERE hobbies.name LIKE "query";