MS Access SQL code - query issue with NOT IN - sql

I'm trying to find out which partners has not paid the monthly tuition in a particular month.
I have a table called Socios containing all partners names SocioNome and another table called RegistroPagamento contaning all payments done (This particular table is fulfilled by a form where the user input the Partner Name, Amount Paid and which particular month/year the payment is related to).
I have created a query where I used the SQL code below:
SELECT [SocioNome]
FROM [Socios] NOT IN
(SELECT [SocioNome] FROM [RegistroPagamento] WHERE [MesBoleto] = [Forms]![Selecionar_MCobranca]![TBoxMes] AND [AnoBoleto] = [Forms]![Selecionar_MCobranca]![TBoxAno]);
[Selecionar_MCobranca] is the form I have mentioned before and the [TBoxMes] & [TBoxAno] are the combo boxes from the form which the user can select the month and the year the payment refers to.
When I run the code, a error message pops up indicating that there is a FORM clause syntax issue, and I don't know exactly what is causing the problem.

NOT IN is a comparison operator in the WHERE clause. It does not belong in the FROM cluase. I strongly recommend using NOT EXISTS instead. The idea is:
SELECT s.SocioNome
FROM Socios as s
WHERE NOT EXISTS (SELECT 1
FROM RegistroPagamento as rp
WHERE rp.MesBoleto = [Forms]![Selecionar_MCobranca]![TBoxMes] AND
rp.AnoBoleto = [Forms]![Selecionar_MCobranca]![TBoxAno] AND
rp.SocioNome = s.SocioNome
);
NOT IN returns no rows if any row in the subquery is NULL. To protect against this, just use NOT EXISTS. It has the expected behavior in this case.

Related

MS Access SQL, sort by age in a specific order

My task: "Compile an SQL query that outputs a specific store (enter parameter window) the age of the youngest buyer"
I´ve tried some things, but because i´m new to SQL and i have no idea what i´m doing non of them seem to work.
I´d really appreciate, if someone would help me.
Thanks!
First you need to know the fields to SELECT (or return) and the table FROM which you are querying (asking) data; let's say you have the following tables: tblStores (containing a list of stores and related info), tblCustomers (containing customers and related info, e.g. ages, names, phone numbers, etc.), and tblPurchases (containing all the purchases at all stores by all customers and related info). You want the minimum age of a customer making a purchase at a specfic store, so you could use a MIN aggregating function. You would want to join (or relate) the tables based on customers and purchases. See my INNER JOINs in the example below. Then you filter the result by the user-inputted store name (inputStoreName) using WHERE; since the inputStoreName is undefined, in Access this would cause the parameter entry popup window to appear.
SELECT list of fields or aggregating functions you want (comma-separated)
FROM list of tables the fields are in (comma-separated) and how to join the tables
WHERE list of conditions to filter the data (separated by AND or OR)
Example:
SELECT tblStores.Name, tblStores.Description, MIN(tblCustomers.age)
FROM tblStores INNER JOIN ( tblPurchases INNER JOIN tblCustomers on tblPurchases.customerID = tblCustomer.customerID) ON tblStores.storeID = tblPurchases.storeID
WHERE (tblStores.Name = inputStoreName);
I recommend checking W3 schools. They are usually helpful for most programming tasks. If you provide more info about your database, we can provide more directed help.

Vb.net query access database table with 2 conditions on the same field

Short background information;
I receive notification emails with an alphanumeric number, a status field, the email receiving time and the sender name.
I have a database which I populated with these outlook emails. E.g.:
Number status receivingtime sender
Xyz12345 new 22.01.2019 20:22:16 abc
Xyz5683 new 23.01.2019 15:45:55 abc
Xyz12345 closed 23.01.2019 14:32:30 abc
Xyz8765 new 24.01.2019 16:55:32 abc
Xyz9999 closed 2t.01.2019 09:10:11 abc
I need a query (number,status,time,sender) which extracts only the new items if they where not already set to status closed.
In the above given example the extracted data should be xyz5683 and xyz8765
I tried already doing this with for loops which I don't really like as the performance is bad.
I also tried this with populating 2 datatables and joining them together, used except within linq. Due to the fact that I like to store it anywhere for further use I also skipped this method. I would prefer
1.) importing all the emails to the access db
2.) Query them as needed
I read tons of articles with different solutions, but can't figure out how to do this....maybe I already got stuck because I'm thinking way too difficult.
Do you have any ideas how I can do this?
You mentioned Access, so my first solution will give you what you want to see.
At the top of your screen on the ribbon/toolbar, you can create a query. Create > Query Design > Close button > SQL View on ribbon.
First, create a new query called "closed" with the SQL as:
Select Distinct [Number] From status_table where status = 'closed'
Then, create what is called a mismatch query:
Select st.[Number], st.status, st.receivingtime, st.sender From status_table as st
Left Join closed as cls on st.[Number] = cls.[Number]
Where cls.[Number] Is Null;
The query will only show rows which are not closed. You can also try the "Find Unmatched Query Wizard" and follow the steps to remove closed items from your list. You will still need to create the query called "closed" before running the wizard.
If you have SQL Server, you can do this in one query:
With cls As --closed items
(Select Distinct [Number]
From status_table where status = 'closed')
Select st.[Number], status, receivingtime, sender From status_table st
Left Join cls on st.[Number] = cls.[Number]
Where cls.[Number] Is Null;
This example is for Microsoft T-SQL but you can do similar queries in other database types like Oracle, with slightly different syntax. Performance should be good in most environments.

Oracle SQL: Show Individual Count Even if There are Duplicates

this is my first question on here, so please forgive me if I break any rules.
Here is what I need to know:
How do I create an Oracle SQL query that will display a unique count of something even if there are duplicates in the results?
Example: a customer table has a list of purchases made by various customers. The table lists the customer ID, name, category of purchase (ie Hardware, Tools, Seasonal) ect. The outcome of the query needs to show each customer id, customer name and the category of the purchase, and a count of the individual customer. SO customer ID 1 for John Smith has made a purchase in each department. If I do a count of the customer, he will appear three times as he has made three purchases, but I also need a column to count the customer only once. The count in the other rows returned for the other departments should show a 0 or Null.
I normally achieve this by pulling everything and exporting to excel. I add a column that uses an IF formula on the ID to only show a 1 on the first occurrence of the customer IE: IF(A3=A2,0,1) (if a3 is the same as A2, show a 0, if it's not the same as A2 then show a 1). This will give me a unique count of customers for one part of the report and will still show me how many purchase the customer made in another part of the report.
I want to do this directly in the SQL query as I have a large set of data this needs to be done on, and adding any formulas in excel will make the sheet huge. This will also make it easier to host the query results in ACCESS so excel can pull it from there.
I have tried to find a solution to this for a while, but any searching on Google will usually return results on how to remove duplicates form a table or how to count the duplicates in a table.
I am sorry if this is long question, but I wanted to be through so I do not waste anyone's time on back an fourth comments (I have seen this many times on here and else where when the OP asks a very cryptic question and expects everyone to understand them without further expiation).
Using distinct can be used in a count to only count the unique values of a field.
SELECT
cust.customer_id, cust.customer_name, p.category,
count(distinct p.department_id) as total_departments,
count(*) as total_purchases
FROM customers cust
LEFT JOIN purchase_table p on (cust.customer_id = p.customer_id)
GROUP BY cust.customer_id, cust.customer_name, p.category
ORDER BY cust.customer_id;
Such method is not limited to the Oracle RDBMS.

Multi-level GROUP BY clause not allowed in subquery

I have a query as follows in MS Access
SELECT tblUsers.Forename, tblUsers.Surname,
(SELECT COUNT(ID)
FROM tblGrades
WHERE UserID = tblUsers.UserID
AND (Grade = 'A' OR Grade = 'B' OR Grade = 'C')) AS TotalGrades
FROM tblUsers
I've put this into a report and now when trying to view the report it displays an alert "Multi-level GROUP BY clause is not allowed in subquery"
What I dont get is I dont even have any GROUP BY clauses in the query so why is it returning this error?
From Allen Browne's excellent website of Access tips: Surviving Subqueries
Error: "Multi-level group by not allowed"
You spent half an hour building a query with subquery, and verifying it all works. You create a report based on the query, and immediately it fails. Why?
The problem arises from what Access does behind the scenes in response to the report's Sorting and Grouping or aggregation. If it must aggregate the data for the report, and that's the "multi-level" grouping that is not permitted.
Solutions
In report design, remove everything form the Sorting and Grouping dialog, and do not try to sum anything in the Report Header or Report Footer. (In most cases this is not a practical solution.)
In query design, uncheck the Show box under the subquery. (This solution is practical only if you do not need to show the results of the subquery in the report.)
Create a separate query that handles the subquery. Use this query as a source "table" for the query the report is based on. Moving the subquery to the lower level query sometimes (not always) avoids the problem, even if the second query is as simple as
SELECT * FROM Query1;
Use a domain aggregate function such as DSum() instead of a subquery. While this is fine for small tables, performance will be unusable for large ones.
If nothing else works, create a temporary table to hold the data for the report. You can convert your query into an Append query (Append on Query menu in query design) to populate the temporary table, and then base the report on the temporary table.
IMPORTANT NOTE: I'm reposting the info here because I believe Allen Browne explicitly allows it. From his website:
Permission
You may freely use anything (code, forms, algorithms, ...) from these articles and sample databases for any purpose (personal, educational, commercial, resale, ...). All we ask is that you acknowledge this website in your code, with comments such as:
'Source: http://allenbrowne.com
'Adapted from: http://allenbrowne.com
Try this version:
SELECT users.Forename, users.Surname, grades.TotalGrades
FROM tblUsers AS users
LEFT JOIN (SELECT COUNT(ID) as TotalGrades, UserID FROM tblGrades WHERE (Grade = 'A' OR Grade = 'B' OR Grade = 'C') group by userid) AS grades on grades.UserID = users.UserID
I have not tested it. The query itself should be OK, but I'm not sure whether it works in the report data source.
try this:
SELECT users.Forename, users.Surname, count(grades.id) AS TotalGrades
FROM tblUsers AS users
INNER JOIN tblGrades AS grades ON users.ID=grades.UserID
WHERE grades.Grade in ("A","B","C") group by users.ID;
This is a simple joined table. Basically it means. Select all cases where a user has a grade with "A" or "B" or "C" (which would give you a table like this:
user1 | A
user1 | B
user1 | A
user2 | A
...
And then it groups it by users, counting how many times a grade appeared -> giving you the number of grades in the desired range for each user.

T SQL WHERE Clause

I'm trying to develop some code which pulls latest information only.
What it is when a user goes into a form there a subtable and everytime they change something it creates a new row in the colum called type12_OriginalNoteID which puts its own unique number in. Another field called type12_OriginalNoteID keeps the same number - which keeps track of what the orginal number was before any changes were made.
I do have some code which does pull the latest information but it does not pull anything if the user has not made any changes to the form - and thats because the type12_OriginalNoteID is null.
The code is as follows :-
WHERE ea.type12_NoteID IN
(SELECT TOP 1 ea.type12_NoteID
FROM UserAssessv1aidsadaptations ea1
WHERE ea.type12_NoteID = ea1.type12_OriginalNoteID
ORDER BY ea.type12_UpdatedDate DESC)
An example of the data is as follows :-
type12_note ID 12
type12_OriginalNoteID NULL
type12_UpdatedDate 11/03/2010
What would be the solution to show the information if no one has made any changes to the subtable? - adding an if statement to run if type12_OriginalNoteID is null??
What you need, is to join the two tables using a LEFT JOIN. So the record data from the main table will be still there, but the fields coming from your second table (= subtable) would be null. Your statement should look something like:
SELECT TOP 1 t1.type12_NoteID
FROM t1 LEFT JOIN t2
ON t1.type12_NoteID = t2.type12_OriginalNoteID
ORDER BY t1.type12_UpdatedDate DESC