Access Report groupig by expression - ms-access

I want to group in my report by value [Order] with exception: if value of [tmp] is equal to 1, they should be grouped together with extra header
I tried
=IIf([tmp]=1;1;[Order])
but it just gives an error "This expression is typed incorrectly ...", basically every expression in grouping with IIf function gives that error, works fine in other parts of access
when i just put
=[Order]
it's fine
Is it just me who don't understand something about how expressions or grouping in access works?

For grouping in a query there are two possibilites:
Use a UNION query:
SELECT Max(YourField) FROM YourTable WHERE Tmp <> 1 GROUP BY [Order]
UNION
SELECT Max(YourField) FROM YourTable WHERE Tmp = 1 GROUP BY Tmp
Use a sub query to create a 'GroupField' based on your condition:
SELECT Max(YourField)
FROM (SELECT *, IIf(Tmp = 1, 1, [Order]) As GroupField FROM YourTable) As SubQuery
GROUP BY GroupField
For grouping only in the report:
You can use the sub query as the record source of your report and then group on the 'virtual' field GroupField:
SELECT *, IIf(Tmp = 1, 1, [Order]) As GroupField FROM YourTable
Info:
Max(YourField) and YourTable are just to get my test query running, because you didn't specify the rest of your query.

Related

Count how many times distinct values repeat in another column with sql

so I got a column with hundreds of different first names and another column with 7 different neighborhoods that repeat multiple times.
I want to check what are the most common names for each neighborhood. How would I go about it?
Thanks and I hope I made my question clear enough.
I tried the below, and got this error - SQL Error: Syntax error: Encountered " "COUNT" "Count "" at line 8, column 5. Was expecting: EOF
SELECT
host_name, neighbourhood_group,
COUNT(*) AS Ct
FROM AB_NYC_2019
GROUP BY
host_name,
neighbourhood_group,
Max Count AS
(
SELECT
*,
MAX(Ct) OVER
(
PARTITION BY neighbourhood_group
) AS MaxCt
FROM Counts
)
SELECT
neighbourhood_group,
host_name
FROM MaxCounts
WHERE Ct = MaxCt;
select * from
(select host_name,neighbourhood_group, RANK() OVER (PARTITION BY neighbourhood_group order by c desc) as RN
from(select host_name,neighbourhood_group,count(*) as c
from AB_NYC_2019 group by host_name,neighbourhood_group)m)n where
RN=1;

What is the other way to get result without using MYSQL ROW_NUMBER Function with PARTITION and multiple group by to reset row count

select
Id,request_id,key_skill_id,
ROW_NUMBER() OVER (PARTITION BY skill_id
ORDER BY request_id,skill_id) sequence
from report
where id= x
GROUP by request_id, skill_id
order by request_id,skill_id ;
I tried to write something like the following, but the result is not the same:
select
id,
request_id,
#skill_id :=skill_id as skill_id,
#row_number :=
CASE
WHEN #skill_id = skill_id THEN #row_number+1
ELSE 1
END AS row_number
from report,
(SELECT #row_number := 0, #skill_id := '') as t
where id =x
GROUP by request_id, skill_id
order by request_id, skill_id;
The original window function strikes me as a bit odd but I confess that I don't use these functions too frequently being confined to MySQL 5.7 myself. The PARTITION BY clause specifies the key_skill_id column so re-numbering 1, 2, 3, etc. will be done on those rows with identical key_skill_id column values. But then there is a final ORDER clause at the very end of the SQL that re-sorts the results so that rows with the same key_skill_id will not in general be together (unless, for example, there was only a single value of feedback_request_id being selected).
To do the initial numbering the rows, however, the table must first be sorted by key_skill_id and then feedback_request_id. The purpose of the GROUP BY clause in the original SQL is to function as an equivalent of a SELECT DISTINCT query, which can't be used because the added row number column guarantees that each row is distinct. The reason why the GROUP BY works is that it is applied before the ROW_NUMBER window function is performed whereas the SELECT DISTINCT implied filtering would be applied after the ROW_NUMBER function is performed.
Given you have provided no table definitions, data, expected output, etc. I was unable to test the following. This is my best guess:
select
x.*,
#row_number :=
CASE
WHEN #key_skill_id = x.key_skill_id THEN #row_number+1
ELSE 1
END AS sequence,
#key_skill_id = x.key_skill_id
from (
select distinct /* to emulate group by */
candidateId,
feedback_id,
key_skill_id
from newFeedbackReport
where candidate_id = 2501
order by key_skill_id, feedback_request /* this is not a mistake */
) x,
(SELECT #row_number := 0, #key_skill_id := '') as t
order by feedback_request_id, key_skill_id;

Invalid use of group function in Lag Function

I am brand new to SQL and have a fairly simple query but I keep getting the error "Invalid use of group function" when trying to use it. Here is my query:
select CreateDate as date,
count(*) as count,
lag(count(*), 1) OVER (order by CreateDate) as Previous
from contacts
Can someone explain why this would not work and how I can get it to function properly?
Your query raises error message:
ER_MIX_OF_GROUP_FUNC_AND_FIELDS: In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'test.contacts.createdate'; this is incompatible with sql_mode=only_full_group_by
This has nothing to do with lag(). Your query is just missing a group by clause:
select
CreateDate as date,
count(*) as count,
lag(count(*), 1) over(order by CreateDate) as previous
from contacts
group by createdate

MySQL - GROUP BY, select only the first row when grouping

I'm having a problem with grouping specific columns into one. When I use GROUP BY, the last row always gets selected when it should be the first row.
The main query is:
SELECT cpme_id,
medicine_main_tbl.med_id,
Concat(med_name, ' (', med_dosage, ') ', med_type) AS Medicine,
med_purpose,
med_quantity,
med_expiredate
FROM medicine_main_tbl
JOIN medicine_inventory_tbl
ON medicine_main_tbl.med_id = medicine_inventory_tbl.med_id
WHERE Coalesce(med_quantity, 0) != 0
AND Abs(Datediff(med_expiredate, Now()))
ORDER BY med_expiredate;
SELECT without GROUP BY
If I GROUP BY using any duplicate column value (in this case, I used med_id):
SELECT with GROUP BY
I'm trying to get this output
Expected Output
The output should only be the first two from the first query. Obviously, I cannot use LIMIT.
Since you are using MariaDB, I recommend using ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY med_id ORDER BY med_expireDate) rn
FROM yourTable
)
SELECT cpme_id, med_id, Medicine, med_purpose, med_quantity, med_expireDate
FROM cte
WHERE rn = 1;
This assumes that the "first" row for a given medicine is the one having the earliest expire date. This was the only interpretation of your data which agreed with the expected output.

Sorting on timestamp column in My Sql - not varchar column

I ma trying to sort SQL tuples based on a column filed which is of timestamp datatype.
The data in the table is something like this :
id attribute value updated
-------------------------------------------------
'3449' 'HEIGHT' '12' '2013-11-30 03:20:25'
'3449' 'HEIGHT' '15' '2013-12-10 03:20:25'
select *, count(1) as cnt from attribute_table
where id ='3449'
group by id,attribute having cnt > 1
ORDER BY updated;
The output is some thing like this, regardless of the fact that I add ASC/DESC parameter at the end of ORDER BY statement, the result remains the same.
id attribute value updated
-------------------------------------------------
'3449' 'HEIGHT' '12' '2013-11-30 03:20:25'
The datatype of updated column is timestamp, and not varchar as other similar questions have had on SO.
How do I sort by updated column ?
The general solution to this type of problem is a two step process. First, find the latest row for each id:
select id, attribute, max(updated) last_updated
from <your_table>
group by id, attribute
Next, we need to join that result, back to the table again to get the rest of the data.
select t.*
from <your_table> t
inner join (
select id, attribute, max(updated) last_updated
from <your_table>
group by id, attribute
) q
on t.id = q.id
and t.updated = q.last_updated
and t.attribute = q.attribute
And that should give you the result you want.
quick demo here
The reason your attempt doesn't work, is down to the way that mysql handles grouping for fields that aren't used in the group by clause, or used in an aggregate function.
It is in fact, a convenience that mysql allows you to select fields in that matter at all, most (if not all) other rdbms will throw an error if you try and do that.
12.16.3 MySQL Handling of GROUP BY will give you the run down, but the important section is this:
You can use this feature to get better performance by avoiding
unnecessary column sorting and grouping. However, this is useful
primarily when all values in each nonaggregated column not named in
the GROUP BY are the same for each group. The server is free to choose
any value from each group, so unless they are the same, the values
chosen are indeterminate.
And that's why it isn't choosing the date or value that you want it to.
You can use variables to identify highest ranking record per id, attribute:
SELECT id, attribute, value, updated
FROM (
SELECT value, updated,
#row_number:= CASE WHEN #id = id AND #attr = attribute THEN #row_number+1
ELSE 1
END AS rn,
#id:=id AS id,
#attr:=attribute AS attribute
FROM attribute_table, (SELECT #row_number:=0, #id:=0, #attr:='') AS vars
ORDER BY id, attribute, updated DESC ) t
WHERE t.rn =1
rn = 1 predicate will select those records having the most recent updated value per id, attribute.
SQL Fiddle Demo
EDIT:
Taking into consideration the comments by #pala_ this is how the query should look like:
SELECT id, attribute, value, updated
FROM (
SELECT id, attribute, value, updated,
if (#id = id AND #attr = attribute,
if (#id:=id,
if (#attr:=attribute, #row_number:= #row_number + 1, #row_number:= #row_number + 1),
if (#attr:=attribute, #row_number:= #row_number + 1, #row_number:= #row_number + 1)
),
if (#id:=id,
if (#attr:=attribute, #row_number:= 1, #row_number:= 1),
if (#attr:=attribute, #row_number:= 1, #row_number:= 1)
)
) AS rn
FROM attribute_table, (SELECT #row_number:=0, #id:='', #attr:='') AS vars
ORDER BY id, attribute, updated DESC ) t
WHERE t.rn = 1
SQL Fiddle Demo
You are using aggregates, group by in mysql takes the first rows of all the rows that are grouped to one row.
Since there are 2 rows that satisfy your group condition so the first (i.e. the top) row is picked for the result set.
you, somehow, need to bring it on the top. A possible turn around, is to sort the result set first, bring the row on top and perform group by.
select *, count(1) as cnt from (select * from attribute_table order by
updated desc ) as alias
where id ='3449'
group by id,attribute having cnt > 1
ORDER BY updated;