paging and ordering a MS Access query - database

i have the following MS ACCESS query that i would like it to return results ordered by name and "paged" by "faking" a rownumber
select * from (SELECT *
FROM (SELECT
s.name as SHolderCategory,
c1.id,
c1.fmember,
c1.link,
m.name as category,
c1.name,
c1.address1,
c1.address2,
c1.city,
c1.state,
c1.zip,
(SELECT COUNT(c2.id) FROM orgs AS c2 WHERE c2.id <= c1.id) AS rownumber
FROM
((orgs AS c1 inner join membershipcls m on m.Id = c1.mClassID)
inner join SHolderscategories s on s.Id = c1.SHolderCategoryID
)
where c1.active = 1)
order by c1.name)
WHERE rownumber > 20 AND rownumber <=40
the problem here is that the ordering is done before the where clause which enforces paging.
so it ends up sorting one page at a time, rather than sorting the whole resultset then paging it...so the results are wrong because in page 1 i have names starting with a to g ... then in page 2 it comes back to names starting with c .... and so on
when i try to get the order clause out so that the query executes the paging first...Mr ACCESS is Angry!!! and tells me it is a COMPLEX query !!!!
any workaround for this?

try also this approach:
SELECT * FROM
(
SELECT TOP 20 *
FROM
(
SELECT TOP 40
s.name as SHolderCategory,
c1.id,
c1.fmember,
c1.link,
m.name as category,
c1.name,
c1.address1,
c1.address2,
c1.city,
c1.state,
c1.zip
FROM
orgs AS c1
inner join membershipcls m on m.Id = c1.mClassID
inner join SHolderscategories s on s.Id = c1.SHolderCategoryID
WHERE c1.active = 1
ORDER BY c1.name
) o
ORDER BY o.name DESC
) f ORDER BY f.name

Related

Narrowing Down IDs to Where a Certain Value of an Attribute Doesn't Exist

I have a list of IDs, and each has multiple [Code] values (in the Code table)
I want to narrow down to IDs that have the following SUBSTRING(Code, LEN(Code) - 3, 4) <> '.003'. My query below:
SELECT m.ID, c.Code FROM MatchID m
LEFT JOIN Code c WITH(NOLOCK)
ON c.ID = m.ID
GROUP BY m.ID, c.Code HAVING SUBSTRING(c.Code, LEN(c.Code) - 3, 4) <> '.003'
ORDER BY m.ID
In this case the GROUP BY HAVING isn't narrowing down to the IDs, but instead just it's rows that don't have Codes ending in '.003'
How do I modify this so it pulls IDs that have no .003 Codes at all?
You must group by ID and put the condition in the HAVING clause:
SELECT m.ID
FROM MatchID m LEFT JOIN Code c
ON c.ID = m.ID
GROUP BY m.ID
HAVING SUM(CASE WHEN RIGHT(c.Code, 4) = '.003' THEN 1 ELSE 0 END) = 0
ORDER BY m.ID
I used the function RIGHT() which is simpler.
Since you have a LEFT JOIN this code will also return unmatched IDs.
If you want only the matched IDs change it to INNER JOIN.
Why you are using group by without any aggregate function in select clause?
Why you are filtering rows with HAVING clause?
Where clause is used to filter rows.
SELECT m.ID, c.Code
FROM MatchID m
LEFT JOIN Code c WITH(NOLOCK) ON c.ID = m.ID
WHERE c.Code NOT LIKE '%.003%'
ORDER BY m.ID

SQL Query Group by Count and Left Join Tables

i need your help! I got some simple SQL skills, but this query kills me...
My Tables
Now i want the TOP5 WorkTimes on the Equipment (What Equipment got the longest WorkTime).
I want this OUTPUT:
MY Query:
SELECT
Equipment, EquipmentName, count(Equipment) as Count
FROM
Operations o
LEFT JOIN Orders ord ON ord.Id = o.[Order]
LEFT OUTER JOIN Equipments e ON ord.Equipment = e.EquipmentNumber
GROUP BY
Equipment, EquipmentName
ORDER BY Count DESC;
Another Question is how i can show o.Worktime?
i got an error with GroupBy...
please help me Thanks!
You can try this query:
select equip_nr,
(select equipmentname from table_equipments where equipmentnr = [to].equip_nr) equip_name,
sum(timeInMins) / 60.0 Worktime
from (
select (select equipmentnr from table_orders where id = [to].[order]) equip_nr,
case when workunittime = 'RH' then worktime * 60 else worktime end timeInMins
from table_operations [to]
where exists(select 1 from table_orders
where [to].[order] = id
and location = '152')
and [start] >= '2018-07-01 00:00:00.000' and [start] < '2018-08-01 00:00:00.000'
) [to] group by equip_nr
By the way, LEFT JOIN is equivalent to LEFT OUTER JOIN.
Just use SUM(worktime) as aggregate function, instead of COUNT(Equipment)
SELECT
e.[ID_Equipment]
, Name
, SUM( IIF(o.WorkUnitTime='MIN', worktime/60.0, worktime) ) as WorktimeMIN
FROM
Operations o
LEFT JOIN Orders ord ON ord.ID_Order = o.ID_Order
LEFT OUTER JOIN Equipment e ON ord.ID_Equipment = e.ID_Equipment
GROUP BY
e.[ID_Equipment]
, Name
ORDER BY
WorktimeMIN DESC
See SQL Fiddle here: http://sqlfiddle.com/#!18/5b5ed/11

SQL Server UNION ALL Merge Join (Concatenation) too slow

I have a select query which utilizes UNION ALL keyword on two tables with same structure (columns and primary key, they have different non-clustered indexes). These two tables contain 39 million rows, a million in one and a 38 million in the other. When running a query just on a table1 which has a million rows, it takes approximately 0.2 seconds, on table2 we have a different situation it takes from 0.5 to 1.2 seconds maximum, depending on the stress of DB.
In reality, for displaying I need to union those two tables, but the problem is that the union query takes a whopping 8 seconds to run. When taking a look at execution plan, the most heavy operation is Merge Join (Concatenation) with the cost of 91%, I am little bit concerned as the WHERE clause I'm running selects 51 entries from table1 and 0 entries from the table2 (larger table).
I can't get my head around it, I've been trying to find any solutions to my problem for last two days now and all I found was either UNION being used instead of UNION ALL or unnecessary clauses being in place like GROUP BY or LEFT/INNER JOINS. Query also does paging, using this commands ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;, all tests (on single tables and with UNION ALL) were performed with paging (OFFSET and FETCH NEXT) keywords in place.
If required, I can provide the table details and query details. It a simple select query with 2 INNER JOINS and 2 LEFT JOINS all of the joined tables contain really small amount of data (ranging from 50 entries to 20K entries).
Here's the query
SELECT *
FROM (SELECT tr.Id,
tr.Amount,
tr.TypeId,
t.Name AS [Type],
tr.Date,
tr.ExternalKey,
tr.ExternalDescription,
tr.GameId,
tr.GameProviderId,
gp.Name AS GameProvider,
u.Username,
u.Pincode,
gp.Name,
g.GameName,
u.OperatorId,
tr.BalanceBefore,
tr.BalanceAfter,
tr.UserId
FROM (
SELECT *
FROM dbo.ActiveTransactions at
WHERE ( 1 = 1 )
AND ( [Date] >= '2017-07-17 20:00:00' )
AND ( [TypeId] != 10 )
AND ( [UserId] = 29041 )
UNION ALL
SELECT *
FROM dbo.TransactionHistory th --WITH(INDEX(IX_TransactionHistory_DateType_UserId))
WHERE ( 1 = 1 )
AND ( [Date] >= '2017-07-17 20:00:00' )
AND ( [TypeId] != 10 )
AND ( [UserId] = 29041 )
) AS tr
INNER JOIN dbo.Users u ON tr.UserId = u.Id
LEFT JOIN dbo.GameProviders gp ON tr.GameProviderId = gp.Id
LEFT JOIN dbo.Games g ON tr.GameId = g.GameId AND tr.GameProviderId = g.ProviderId
INNER JOIN dbo.Types t ON tr.TypeId = t.Id ) AS t
ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;
This is an educated guess: without knowledge of indexes or execution plan on what the engine is actually getting caught up on.
Consider: Doing the union after the joins/filters instead of before: you have to repeat the joins but you may gain some index efficiency's lost in a unioned set processing.
In this case I created two CTE's and then unioned them.
as I'm unable to really test this, I may have some syntax errors.
WITH cte1 AS
(SELECT tr.Id,
tr.Amount,
tr.TypeId,
t.Name AS [Type],
tr.Date,
tr.ExternalKey,
tr.ExternalDescription,
tr.GameId,
tr.GameProviderId,
gp.Name AS GameProvider,
u.Username,
u.Pincode,
gp.Name,
g.GameName,
u.OperatorId,
tr.BalanceBefore,
tr.BalanceAfter,
tr.UserId
FROM (
SELECT *
FROM dbo.ActiveTransactions at
WHERE ( 1 = 1 )
AND ( [Date] >= '2017-07-17 20:00:00' )
AND ( [TypeId] != 10 )
AND ( [UserId] = 29041 )) AS tr
INNER JOIN dbo.Users u ON tr.UserId = u.Id
LEFT JOIN dbo.GameProviders gp ON tr.GameProviderId = gp.Id
LEFT JOIN dbo.Games g ON tr.GameId = g.GameId AND tr.GameProviderId = g.ProviderId
INNER JOIN dbo.Types t ON tr.TypeId = t.Id ) AS t),
CTE2 as (
SELECT tr.Id,
tr.Amount,
tr.TypeId,
t.Name AS [Type],
tr.Date,
tr.ExternalKey,
tr.ExternalDescription,
tr.GameId,
tr.GameProviderId,
gp.Name AS GameProvider,
u.Username,
u.Pincode,
gp.Name,
g.GameName,
u.OperatorId,
tr.BalanceBefore,
tr.BalanceAfter,
tr.UserId
FROM (SELECT *
FROM dbo.TransactionHistory th --WITH(INDEX(IX_TransactionHistory_DateType_UserId))
WHERE ( 1 = 1 )
AND ( [Date] >= '2017-07-17 20:00:00' )
AND ( [TypeId] != 10 )
AND ( [UserId] = 29041 ) as tr
INNER JOIN dbo.Users u ON tr.UserId = u.Id
LEFT JOIN dbo.GameProviders gp ON tr.GameProviderId = gp.Id
LEFT JOIN dbo.Games g ON tr.GameId = g.GameId AND tr.GameProviderId = g.ProviderId
INNER JOIN dbo.Types t ON tr.TypeId = t.Id) AS t
)
SELECT * from CTE1
UNION ALL
SELECT * from CTE2
ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;

Group nested selected query returning all rows

I'm trying to display the data so that only one line is displayed per customer, i'm having trouble with trying to achieve that with my code as its returning all records, can anyone help
SELECT customerOrdrs.NAME AS 'Name',
customerOrdrs.currentbalance -
Sum(COALESCE(customerOrdrs.revisedbalance, 0)) AS 'RevisedBalance',
sold AS 'NumberOfItemsSold'
FROM customers,
(SELECT c.NAME AS NAME,
c.balance AS CurrentBalance,
i.qty AS RevisedBalance,
( Min(s.price) * i.qty ) AS Sold
FROM customers c
INNER JOIN sales o
ON c.NAME = o.custname
INNER JOIN purchases i
ON i.orderno = o.orderno
INNER JOIN contracters s
ON i.item = s.item
GROUP BY c.NAME,
c.balance,
i.qty) customerOrdrs
GROUP BY customerOrdrs.NAME,
customerOrdrs.currentbalance,
sold
I'm not sure how your data looks but I have reformatted the query and there are a few things I've noticed off the bat.
I have removed the subquery as I don't believe it is necessary - in addition your original query is referring to customer table twice without defining a join
Select [C].[Name] As [Name]
, [CurrentBalance] = [C].[Balance]
, [RevisedBalance] = [C].[Balance] - Sum([P].[Qty])
, [Sold] = ( Min([CO].[Price]) * sum([P].[Qty]) )
From [CUSTOMERS] [C]
Inner Join [Sales] [s]
On [C].[Name] = [s].[custName]
Inner Join [Purchases] [P]
On [P].[OrderNo] = [s].[OrderNo]
Inner Join [Contracters] [CO]
On [P].[Item] = [CO].[Item]
Group By [C].[Name]
, [C].[Balance];

How to Compare Max(Count(*)) value without using SubQuery in MS SQL?

I want to compare count(*) value with max(count(*)) value without using whole query in subquery block. The related example is shown below. Please suggest me a shortest and best way to achieve the same result?
select ee.LocationName
from Employees ee
inner join EmployeeActivities ea on ee.Username = ea.Username
where ea.Activity = 'Hospital'
group by LocationName
having count(*) =
(
select max(VisitCount)
from (select LocationName, count(*) as VisitCount
from Employees e
inner join EmployeeActivities ea on e.Username = ea.Username
where ea.Activity = 'Hospital'
group by e.LocationName) as a
)
Use this:
select top 1 with ties ee.LocationName
from Employees ee
inner join EmployeeActivities ea on ee.Username = ea.Username
where ea.Activity = 'Hospital'
group by LocationName
order by count(*) desc
Just order descending by count and select top ones(with ties will select all groups with max count).

Resources