In the query below I want to retrieve #MaximumRecords rows, so that no ProjectId will have rows left out beyond #MaximumRecords.
For example if #MaximumRecords=100, and ProjectId=7 has records at rows number 99-102, I wish to retrieve only rows with ProjectId=1 to ProjectId=6 (The query will run again later starting at ProjectId=7). How do I do that?
SELECT TOP (#MaximumRecords)
t1.ProjectId,
t1.Row2,
t2.Row3
FROM Table1 t1
JOIN Table2 t2 ON t1.ProjectId = t2.ProjectId
ORDER BY
t1.ProjectId ASC
WHERE
t1.ProjectId > #InitialProjectId
I worked up a solution using the Sales.SalesOrderHeader and Sales.SalesOrderDetail tables in the AdventureWorks2008R2 database using the technique to get a running total described here.
The basic idea is to get the running total of the count for each SalesOrderID (ProjectID in your case) and then select all of the data for each SalesOrderID where the running total of the count is less than #MaximumRecords. You would then need to capture the maximum ID in the data returned and use that value in the next run of your query.
This task gets a little easier with SQL Server 2012 which is also described in the link given above.
Here it is...
USE AdventureWorks2008R2
IF OBJECT_ID('tempdb..#Test', 'U') IS NOT NULL DROP TABLE #Test;
DECLARE #MaximumRecords INT
DECLARE #InitialSalesOrderID INT
SET #MaximumRecords = 500
SET #InitialSalesOrderID = 43663
SELECT a.SalesOrderID, COUNT(*) AS 'Count'
INTO #Test
FROM Sales.SalesOrderHeader a
INNER JOIN Sales.SalesOrderDetail b ON a.SalesOrderID = b.SalesOrderID
WHERE a.SalesOrderID > #InitialSalesOrderID
GROUP BY a.SalesOrderID
SELECT * FROM Sales.SalesOrderHeader a
INNER JOIN Sales.SalesOrderDetail b ON a.SalesOrderID = b.SalesOrderID
WHERE a.SalesOrderID IN (
SELECT
a.SalesOrderID
FROM
#Test a
WHERE (
SELECT
SUM(Count)
FROM
#Test b
WHERE
b.SalesOrderID <= a.SalesOrderID
) < #MaximumRecords
)
Noel
Related
Let's assume I have 2 tables. One contains car manufacturer's names and their IDs, the second contains information about car models. I need to select few of them from the first table, but order them by quantity of linked from the second table data.
Currently, my query looks like this:
SELECT DISTINCT `manufacturers`.`name`,
`manufacturers`.`cars_link`,
`manufacturers`.`slug`
FROM `manufacturers`
JOIN `cars`
ON manufacturers.cars_link = cars.manufacturer
WHERE ( NOT ( `manufacturers`.`cars_link` IS NULL ) )
AND ( `cars`.`class` = 'sedan' )
ORDER BY (SELECT Count(*)
FROM `cars`
WHERE `manufacturers`.cars_link = `cars`.manufacturer) DESC
It was working ok for my table of scooters which size is few dozens of mb. But now i need to do the same thing for the cars table, which size is few hundreds megabytes. The problem is that the query takes very long time, sometimes it even causes nginx timeout. Also, i think, that i have all the necesary database indexes. Is there any alternative for the query above?
lets try to use subquery for your count instead.
select * from (
select distinct m.name, m.cars_link, m.slug
from manufacturers m
join cars c on m.cars_link=c.manufacturer
left join
(select count(1) ct, c1.manufacturer from manufacturers m1
inner join cars_link c2 on m1.cars_link=c2.manufacturer
where coalesce(m1.cars_link, '') != '' and c1.class='sedan'
group by c1.manufacturer) as t1
on t1.manufacturer = c.manufacturer
where coalesce(m.cars_link, '') != '' and c.class='sedan') t2
order by t1.ct
This has to be a no brainer, but I am stumped. I'm used to using aggregate 'FIRST' in MsAccess, but MySql has no such thing.
Here is a simple table. I want to return the most recent record based on the date,
for each unique 'group ID'. I need the three records in yellow.
I was asked to add my full query. I tried one of the suggestions using the JOIN feature replacing 't' with the temp table name, but it failed to work. "Can't reopen table 't'"
The code is below. I know it's ugly, but it does return the correct data set.
I cleaned up the code a bit and added the JOIN code. Error: "Can't reopen table 't'"
enter code here
DROP TABLE IF EXISTS `tmpMaxLookupResults`;
create temporary table tmpMaxLookupResults
as
SELECT
REPORTS.dtmReportCompleted,
RESULTS.lngMainReport_ID, RESULTS.lngLocationGroupSub_ID
FROM
(tbl_010_040_ProcedureVsTest_Sub as ProcVsSub
INNER JOIN tbl_010_050_CheckLog_RESULTS as RESULTS
ON (ProcVsSub.lngLocationGroupSub_ID = RESULTS.lngLocationGroupSub_ID)
AND (ProcVsSub.lngProcedure_ID = RESULTS.lngProcedure_ID)
AND (ProcVsSub.lngItemizedTestList_ID = RESULTS.lngItemizedTestList_ID)
AND (ProcVsSub.strPasscodeAdmin = RESULTS.strPasscodeAdmin)
AND (ProcVsSub.strCFICode = RESULTS.strCFICode))
INNER JOIN
tbl_000_010_MAIN_REPORT_INFO as REPORTS ON (RESULTS.lngPCC_ID =
REPORTS.lngPCC_ID)
AND (RESULTS.lngProcedure_ID = REPORTS.lngProcedure_ID)
AND (RESULTS.lngMainReport_ID = REPORTS.idMainReport_ID)
AND (RESULTS.strPasscodeAdmin = REPORTS.strPasscodeAdmin)
AND (RESULTS.strCFICode = REPORTS.strCFICode)
WHERE
(((RESULTS.lngProcedure_ID) = 143)
AND ((RESULTS.dtmExpireDate) IS NOT NULL)
AND ((RESULTS.strCFICode) = 'ems'))
GROUP BY RESULTS.lngMainReport_ID, RESULTS.lngLocationGroupSub_ID
ORDER BY (REPORTS.dtmReportCompleted) DESC;
SELECT t.*
FROM tmpMaxLookupResults AS t
JOIN (
SELECT lngLocationGroupSub_ID,
MAX(dtmReportCompleted) AS max_date_completed
FROM tmpMaxLookupResults
GROUP BY lngLocationGroupSub_ID ) AS dt
ON dt.lngLocationGroupSub_ID = t.lngLocationGroupSub_ID AND
dt.max_date_completed = t.dtmReportCompleted
enter code here
Try this
SELECT
tn.*
FROM
tableName tn
RIGHT OUTER JOIN
(
SELECT
groupId, MAX(date_completed) as max_date_completed
FROM
tableName
GROUP BY
groupId
) AS gt
ON
(gt.max_date_completed = nt.date_completed AND gt.groupId = nt.groupId)
You can use the following SQL.
select * from table1 order by date_completed desc Limit 1;
Use Order By
SELECT *
FROM table_name
ORDER BY your_date_column_name
DESC
LIMIT 1
In a Derived Table, get the maximum date_completed value for every group_id.
Join this result-set back to the main table, in order to get the complete row corresponding to maximum date_completed value for every group_id
Try the following query:
SELECT t.*
FROM your_table_name AS t
JOIN (
SELECT group_id,
MAX(date_completed) AS max_date_completed
FROM your_table_name
GROUP BY group_id
) AS dt
ON dt.group_id = t.group_id AND
dt.max_date_completed = t.date_completed
I have a query which gets the correct result but it is taking 5.5 sec to get the output.. Is there any other way to write a query for this -
SELECT metricName, metricValue
FROM Table sm
WHERE createdtime = (
SELECT MAX(createdtime)
FROM Table b
WHERE sm.metricName = b.metricName
AND b.sinkName='xx'
)
AND sm.sinkName='xx'
In your code, the subselect has to be run for every result row of the outer query, which should be quite expensive. Instead, you could select your filter data in a separate query and join both accordingly:
SELECT `metricName`, `metricValue` FROM Table sm
INNER JOIN (SELECT max(`createdtime`) AS `maxTime, `metricName` from Table b WHERE b.sinkName='xx' GROUP BY `metricName` ) filter
ON (sm.`createdtime` = filter.`maxTime`) AND ( sm.`metricName` = filter.`metricName`)
WHERE sm.sinkName='xx'
I am trying to retrieve the max(date_entered) for a group of computer_ids.
The first query won't return accurate results. The second query gives me accurate results but essentially hangs unless I filter by a specific computer_id.
I'd rather use this first query
SELECT *, max(reports.date_entered)
FROM reports, hardware_reports
WHERE reports.report_id=hardware_reports.report_id
GROUP BY computer_id;
than this second query
SELECT *
FROM reports a
JOIN hardware_reports
ON a.report_id=hardware_reports.report_id
AND a.date_entered = (
SELECT MAX(date_entered)
FROM reports AS b
WHERE a.computer_id = b.computer_id)
and computer_id = 1648;
I need to either optimize second or get max to work in first.
You can alternative join it on a subquery that gets the latest record for every computer_ID.
SELECT a.*, c.*
FROM reports a
INNER JOIN
(
SELECT computer_ID, MAX(date_entered) date_entered
FROM reports
GROUP BY computer_ID
) b ON a.computer_ID = b.computer_ID
AND a.date_entered = b.date_entered
INNER JOIN hardware_reports c
ON a.report_id = c.report_id
To make it more efficient, provide an index on columns:
ALTER TABLE reports INDEX idx_report_compDate (computer_ID, date_entered)
Everything in the following query results in one line for each invBlueprintTypes row with the correct information. But I'm trying to add something to it. See below the codeblock.
Select
blueprintType.typeID,
blueprintType.typeName Blueprint,
productType.typeID,
productType.typeName Item,
productType.portionSize,
blueprintType.basePrice * 0.9 As bpoPrice,
productGroup.groupName ItemGroup,
productCategory.categoryName ItemCategory,
blueprints.productionTime,
blueprints.techLevel,
blueprints.researchProductivityTime,
blueprints.researchMaterialTime,
blueprints.researchCopyTime,
blueprints.researchTechTime,
blueprints.productivityModifier,
blueprints.materialModifier,
blueprints.wasteFactor,
blueprints.maxProductionLimit,
blueprints.blueprintTypeID
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
So what I need to get in here is the following table with the columns below it so I can use the values timestamp and sort the entire result by profitHour
tablename: invBlueprintTypesPrices
columns: blueprintTypeID, timestamp, profitHour
I need this information with the following select in mind. Using a select to show my intention of the JOIN/in-query select or whatever that can do this.
SELECT * FROM invBlueprintTypesPrices
WHERE blueprintTypeID = blueprintType.typeID
ORDER BY timestamp DESC LIMIT 1
And I need the main row from table invBlueprintTypes to still show even if there is no result from the invBlueprintTypesPrices. The LIMIT 1 is because I want the newest row possible, but deleting the older data is not a option since history is needed.
If I've understood correctly I think I need a subquery select, but how to do that? I've tired adding the exact query that is above with a AS blueprintPrices after the query's closing ), but did not work with a error with the
WHERE blueprintTypeID = blueprintType.typeID
part being the focus of the error. I have no idea why. Anyone who can solve this?
You'll need to use a LEFT JOIN to check for NULL values in invBlueprintTypesPrices. To mimic the LIMIT 1 per TypeId, you can use the MAX() or to truly make sure you only return a single record, use a row number -- this depends on whether you can have multiple max time stamps for each type id. Assuming not, then this should be close:
Select
...
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Left Join (
SELECT MAX(TimeStamp) MaxTime, TypeId
FROM invBlueprintTypesPrices
GROUP BY TypeId
) blueprintTypePrice On blueprints.blueprintTypeID = blueprintTypePrice.typeID
Left Join invBlueprintTypesPrices blueprintTypePrices On
blueprintTypePrice.TypeId = blueprintTypePrices.TypeId AND
blueprintTypePrice.MaxTime = blueprintTypePrices.TimeStamp
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
Order By
blueprintTypePrices.profitHour
Assuming you might have the same max time stamp with 2 different records, replace the 2 left joins above with something similar to this getting the row number:
Left Join (
SELECT #rn:=IF(#prevTypeId=TypeId,#rn+1,1) rn,
TimeStamp,
TypeId,
profitHour,
#prevTypeId:=TypeId
FROM (SELECT *
FROM invBlueprintTypesPrices
ORDER BY TypeId, TimeStamp DESC) t
JOIN (SELECT #rn:=0) t2
) blueprintTypePrices On blueprints.blueprintTypeID = blueprintTypePrices.typeID AND blueprintTypePrices.rn=1
You don't say where you are putting the subquery. If in the select clause, then you have a problem because you are returning more than one value.
You can't put this into the from clause directly, because you have a correlated subquery (not allowed).
Instead, you can put it in like this:
from . . .
(select *
from invBLueprintTypesPrices ibptp
where ibtp.timestamp = (select ibptp2.timestamp
from invBLueprintTypesPrices ibptp2
where ibptp.blueprintTypeId = ibptp2.blueprintTypeId
order by timestamp desc
limit 1
)
) ibptp
on ibptp.blueprintTypeId = blueprintType.TypeID
This identifies the most recent records for all the blueprintTypeids in the subquery. It then joins in the one that matches.