Ignore a column in MS ACCESS query if the WHERE clause is not set - sql

Problem
I've got a dropdown list, which shows all the Article_Group_ID's that are linked to a specific brand, using the following Query:
SELECT TbArticle.Article_Group_ID, TbArticle.Article_Brand_ID
FROM TbArticle
GROUP BY TbArticle.Article_Group_ID, TbArticle.Article_Brand_ID,
HAVING (((TbArticle.Article_Brand_ID)=1))
This works as expected, it returns the following:
Query results
Article_Brand_ID
Article_Group_ID
1
1
1
2
But, if a user does not wish to specify a specific Article_Brand_ID, the query results look like this:
Query
Article_Brand_ID
Article_Group_ID
1
1
2
1
3
1
1
2
As you can see, the same Article_Group_ID is returned three times. Because of this, the user now sees the same group three times, instead of just once. If I were to remove the Article_Brand_ID from the query, the results would look like this:
Article_Group_ID
1
2
Is there any way to achieve the same behavior, by "ignoring" the Article_Brand_ID column, if it's WHERE clause is not set?
Database layout
TbArticle
Article_Brand_ID
Article_Group_ID
1
1
2
1
3
1
1
2

A single query cannot return a variable number of columns. So, strictly speaking you cannot do what you want with a single query. However, if you are willing to accept the second column as NULL when the brand is not provided, then you can adjust the aggregation.
Let me denote the parameter by ?:
SELECT a.Article_Group_ID,
IIF(? IS NOT NULL, a.Article_Brand_ID, NULL) as Article_Brand_ID
FROM TbArticle as a
WHERE a.Article_Brand_ID = ? OR
? IS NULL
GROUP BY a.Article_Group_ID,
IIF(? IS NOT NULL, a.Article_Brand_ID, NULL);
Note: It is usually better to filter before aggregating (i.e. using WHERE) rather than filtering afterwards (i.e. using HAVING).

Related

ISNULL with aggregate function

What is the best way to go about using these two together? In my case if a userID is null I want to return zero, and users can have multiple ID's so we want to have get the lowest (the original) one.
ISNULL(MIN(UserId),0)
Or,
MIN(ISNULL(UserId),0)
Thank you.
Is the answer indicative of all aggregate functions?
Those statements do not necessarily produce the same output:
the first takes the minimum that exists and only if that is null, uses 0.
the second checks each user id and if that is null uses 0 - it then takes the minimum of those (and unless a user ID can be negative, a user with a 5 and a null, would output 0)
A quick script can demonstrate this :
with testData as (
select 1 as SomeKey, 5 as userID
union all
select 1 as SomeKey, null as userID
union all
select 2 as SomeKey, 6 as userID
union all
select 2 as SomeKey, 5 as userID
)
select
somekey
, isnull(min(userid),0) as firstScenario
, min(isnull(userid,0)) as SecondScenario
from testdata
group by somekey
Results:
Somekey firstScenario secondScenario
1 5 0
2 5 5
The first scenario is the most likely one you were after, but the phrasing of the question makes it a bit ambiguous as to what the desired behaviour was.
(http://sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/10170)
It depends on what you want to do. But I am biased towards COALESCE() because it is the ANSI standard function.
Your two options are:
COALESCE(MIN(UserId), 0)
MIN(COALESCE(UserId, 0))
These do not do the same thing. The first returns the minimum user id. If all user ids are NULL, then this expression returns 0.
The second replaces each NULL with 0. Assuming the user ids are positive, then this returns 0 if any user ids are NULL.
Based on my understanding of your logic, you want the second version.
I suppose you use SQL Server, bacause ISNULL is a T-Sql function.
To use a function accross DBMS you can use COALESCE
NULL values are not included in MIN functions.
So If you want to prevent NULL result, I advice you to use the first solution
ISNULL(MIN(UserId), 0)

SQL list only unique / distinct values

I have a table which contains geometry lines (ways).There are lines that have a unique geometry (not repeating) and lines which have the same geometry (2,3,4 and more). I want to list only unique ones. If there are, for example, 2 lines with the same geometry I want to drop them. I tried DISTINCT but it also shows the first result from duplicated lines. I only want to see the unique ones.
I tried window function but I get similar result (I get a counter on first line from the duplicating ones). Sorry for a newbie question but I'm learning :) Thanks!
Example:
way|
1 |
1 |
2 |
3 |
3 |
4 |
Result should be:
way|
2 |
4 |
That actually worked. Thanks a lot. I also have other tags in this table for every way (name, ref and few other tags) When I add them to the query I loose the segregation.
select count(way), way, name
from planet_osm_line
group by way, name
having count(way) = 1;
Without "name" in the query I get all unique values listed but I want to keep "name" for every line. With this example I stilll get all the lines in the table listed.
To expound on #Nithila answer:
select count(way), way
from your_table
group by way
having count(way) = 1;
You first calculate the rows you want, and then search for the rest of the fields. So the aggregation doesnt cause you problems.
WITH singleRow as (
select count(way), way
from planet_osm_line
group by way
having count(way) = 1
)
SELECT P.*
FROM planet_osm_line P
JOIN singleRow S
ON P.way = S.way
you can group by way and while taking the data out check the count=1.It will give non duplicating data.
#voyteck
As I understood your question you need to get only non duplicating records of way column and for each row you need to show the name is it
If so, you have to put all the column in select statement, but no need to group by all the columns.
select count(way), way, name
from planet_osm_line
group by way
having count(way) = 1;

Multicriteria Insert/Update

I'm trying to create a query that will insert new records to a table or update already existing records, but I'm getting stuck on the filtering and grouping for the criteria I want.
I have two tables: tbl_PartInfo, and dbo_CUST_BOOK_LINE.
I'm want to select from dbo_CUST_BOOK_LINE based upon the combination of CUST_ORDER_ID, CUST_ORDER_LINE_NO, and REVISION_ID. Each customer order can have multiple lines, and each line can have multiple revision. I'm trying to select the unique combinations of each order and it's connected lines, but take the connected information for the row with the highest value in the revision column.
I want to insert/update from dbo_CUST_BOOK_LINE the following columns:
CUST_ORDER_ID
PART_ID
USER_ORDER_QTY
UNIT_PRICE
I want to insert/update them into tbl_PartInfo as the following columns respectively:
JobID
DrawingNumber
Quantity
UnitPrice
So if I have the following rows in dbo_CUST_BOOK_LINE (PART_ID omitted for example)
CUST_ORDER_ID CUST_ORDER_LINE_NO REVISION_ID USER_ORDER_QTY UNIT_PRICE
SCabc 1 1 0 100
SCabc 1 2 4 150
SCabc 1 3 4 125
SCabc 2 3 2 200
SCxyz 1 1 0 0
SCxyz 1 2 3 50
It would return
CUST_ORDER_ID CUST_ORDER_LINE_NO (REVISION_ID) USER_ORDER_QTY UNIT_PRICE
SCabc 1 3 4 125
SCabc 2 3 2 200
SCxyz 1 2 3 50
but with PART_ID included and without REVISION_ID
So far, my code is just for the inset portion as I was trying to get the correct records selected, but I keep getting duplicates of CUST_ORDER_ID and CUST_ORDER_LINE_NO.
INSERT INTO tbl_PartInfo ( JobID, DrawingNumber, Quantity, UnitPrice, ProductFamily, ProductCategory )
SELECT dbo_CUST_BOOK_LINE.CUST_ORDER_ID, dbo_CUST_BOOK_LINE.PART_ID, dbo_CUST_BOOK_LINE.USER_ORDER_QTY, dbo_CUST_BOOK_LINE.UNIT_PRICE, dbo_CUST_BOOK_LINE.CUST_ORDER_LINE_NO, Max(dbo_CUST_BOOK_LINE.REVISION_ID) AS MaxOfREVISION_ID
FROM dbo_CUST_BOOK_LINE, tbl_PartInfo
GROUP BY dbo_CUST_BOOK_LINE.CUST_ORDER_ID, dbo_CUST_BOOK_LINE.PART_ID, dbo_CUST_BOOK_LINE.USER_ORDER_QTY, dbo_CUST_BOOK_LINE.UNIT_PRICE, dbo_CUST_BOOK_LINE.CUST_ORDER_LINE_NO;
This has been far more complicated that anything I've done so far, so any help would be greatly appreciated. Sorry about the long column names, I didn't get to choose them.
I did some research and think I found a way to make it work, but I'm still testing it. Right now I'm using three queries, but it should be easily simplified into two when complete.
The first is an append query that takes the two columns I want to get distinct combo's from and selects them and using "group by," while also selecting max of the revision column. It appends them to another table that I'm using called tbl_TempDrop. This table is only being used right now to reduce the number of results before the next part.
The second is an update query that updates tbl_TempDrop to include all the other columns I wanted by setting the criteria equal to the three selected columns from the first query. This took an EXTREMELY long time to complete when I had 700,000 records to work with, hence the use of the tbl_TempDrop.
The third query is a basic append query that appends the rows of tbl_TempDrop to the end destination, tbl_PartInfo.
All that's left is to run all three in a row.
I didn't want to include the full details of any tables or queries yet until I ensure that it works as desired, and because some of the names are vague since I will be using this method for multiple query searches.
This website helped me a little to make sure I had the basic idea down. http://www.techonthenet.com/access/queries/max_query2_2007.php
Let me know if you see any flaws with the ideology!

SQL ORDER BY 0 (int) needs to be first

I am attempting to sort an integer field in ASC order, but it is automatically putting the "0" value near the bottom (just above NULL values).
I am using SQL Server 2005. I think my DBMS is outdated, because I attempted to use NULLS FIRST, and it was not recognized.
*Edited to show better query (thanks for the quick feedback)
What I want to see:
PriSortOrder/CommunityName
0/Towson
1/Atlanta
2/Baltimore
NULL
What I see:
PriSortOrder/CommunityName
1/Atlanta
2/Baltimore
0/Towson
NULL
Query:
SELECT PriSortOrder, CommunityName
FROM Communities
WHERE InCatalog=1
ORDER BY PriSortOrder
Until you show the PrioritySortOrder value as well as the Community value, you can't say that the data is in the right (or wrong) order. For example, if the data is:
Community PrioritySortOrder
0 5
1 0
2 3
NULL 6
You will get the output:
1
2
0
NULL
If the data is:
Community PrioritySortOrder
0 0
1 1
2 2
NULL 3
then you will get the result:
0
1
2
NULL
You can fix your SQL by (adding a FROM table clause and) ordering by Community instead of PrioritySortOrder (though whether the NULL comes first or last depends on your DBMS).

Access SQL how to make an increment in SELECT query

I Have an SQL query giving me X results, I want the query output to have a coulmn called
count making the query somthing like this:
count id section
1 15 7
2 3 2
3 54 1
4 7 4
How can I make this happen?
So in your example, "count" is the derived sequence number? I don't see what pattern is used to determine the count must be 1 for id=15 and 2 for id=3.
count id section
1 15 7
2 3 2
3 54 1
4 7 4
If id contained unique values, and you order by id you could have this:
count id section
1 3 2
2 7 4
3 15 7
4 54 1
Looks to me like mikeY's DSum approach could work. Or you could use a different approach to a ranking query as Allen Browne described at this page
Edit: You could use DCount instead of DSum. I don't know how the speed would compare between the two, but DCount avoids creating a field in the table simply to store a 1 for each row.
DCount("*","YourTableName","id<=" & [id]) AS counter
Whether you go with DCount or DSum, the counter values can include duplicates if the id values are not unique. If id is a primary key, no worries.
I frankly don't understand what it is you want, but if all you want is a sequence number displayed on your form, you can use a control bound to the form's CurrentRecord property. A control with the ControlSource =CurrentRecord will have an always-accurate "record number" that is in sequence, and that will update when the form's Recordsource changes (which may or may not be desirable).
You can then use that number to navigate around the form, if you like.
But this may not be anything like what you're looking for -- I simply can't tell from the question you've posted and the "clarifications" in comments.
The only trick I have seen is if you have a sequential id field, you can create a new field in which the value for each record is 1. Then you do a running sum of that field.
Add to your query
DSum("[New field with 1 in it]","[Table Name]","[ID field]<=" & [ID Field])
as counterthing
That should produce a sequential count in Access which is what I think you want.
HTH.
(Stolen from Rob Mills here:
http://www.access-programmers.co.uk/forums/showthread.php?p=160386)
Alright, I guess this comes close enough to constitute an answer: the following link specifies two approaches: http://www.techrepublic.com/blog/microsoft-office/an-access-query-that-returns-every-nth-record/
The first approach assumes that you have an ID value and uses DCount (similar to #mikeY's solution).
The second approach assumes you're OK creating a VBA function that will run once for EACH record in the recordset, and will need to be manually reset (with some VBA) every time you want to run the count - because it uses a "static" value to run its counter.
As long as you have reasonable numbers (hundreds, not thousands) or records, the second approach looks like the easiest/most powerful to me.
This function can be called from each record if available from a module.
Example: incrementingCounterTimeFlaged(10,[anyField]) should provide your query rows an int incrementing from 0.
'provides incrementing int values 0 to n
'resets to 0 some seconds after first call
Function incrementingCounterTimeFlaged(resetAfterSeconds As Integer,anyfield as variant) As Integer
Static resetAt As Date
Static i As Integer
'if reset date < now() set the flag and return 0
If DateDiff("s", resetAt, Now()) > 0 Then
resetAt = DateAdd("s", resetAfterSeconds, Now())
i = 0
incrementingCounterTimeFlaged = i
'if reset date > now increments and returns
Else
i = i + 1
incrementingCounterTimeFlaged = i
End If
End Function
autoincrement in SQL
SELECT (Select COUNT(*) FROM table A where A.id<=b.id),B.id,B.Section FROM table AS B ORDER BY B.ID Asc
You can use ROW_NUMBER() which is in SQL Server 2008
SELECT ROW_NUMBER() OVER (ORDER By ID DESC) RowNum,
ID,
Section
FROM myTable
Then RowNum displays sequence of row numbers.