Order by not sorting as expected - mysql

I'm using following query:
SELECT plan.datum, plan.anketa, plan.ai as autoinc, plan.objekt as sifra , objekt.sifra, objekt.temp4_da FROM plan
LEFT JOIN objekt ON plan.objekt = objekt.sifra WHERE objekt.temp4_da = '1'
AND objekt.sifra >= 30 AND plan.datum > '2019-01-15' and plan.datum < '2019-01-30'
GROUP BY objekt.sifra
ORDER BY plan.datum ASC, plan.objekt ASC
I get results which is sorted by the last records, though I did put it sorted by date.
Results should be from 2019-01-15, but as you can see its sorted to last date plan.datum < '2019-01-30'...
How can I achive this?
EDIT:
When I select from 2019-01-15 to 2019-01-20 I achive this:

Your result comes from the ability of MySQL to process incorrect SQL queries with GROUP BY. For example, most of the DBMS is not capable to process query like this
SELECT col1, col2
FROM tab
GROUP BY col1
Some DBMS process this query if col1 is the primary key of tab, however, MySQL process it always and it returns a RANDOM col2 value if there are more than one col2 values corresponding to col1! For example, having table
col1 | col2
-----------
a | 1
a | 2
then MySQL may return (a, 1) result on Monday, and (a, 2) on Tuesday using my SQL query shown above (I'm little sarcastic).
I believe that is also your case. MySQL picks random plan.datum for each objekt.sifra (the group by attribute in your query) and you subsequently miss some plan.datum values in the result. Fix your query to obtain deterministic values and you will get rid of your problems.

Given that it does seem to have sorted how you wanted the first 4 rows shows that, those dates are all in the range specified.
You need to just go through basic diagnosis:
Does 'plan' table actually contain data with those dates?
If it does, then the data is being removed by your query.
So the next easiest to check is the WHERE, so remove the other clauses (i.e. leave the 'datum' restrictions), does that data now appear?
If it still doesn't, then the LEFT JOIN is the issue, as joins are filters too.
If you do those and the data appears, then the data and your understanding of the data don't match, and you need to check/confirm any assumptions about the data you may have made.
I'm not 100% familiar with mysql, but the GROUP BY looks really odd, your not doing any sums, mins, or operations on the group. Do you need that line?

Related

MySQL max() followed by ORDER BY

I'm working with a MySql table. The table contains numeric values and unix date values only. Each row has a unique id, columns containing ids related to other parts of the db, totals (like downloads per day) and the date that the row was inserted. My queries need to get the latest date for each id combination, in order to get the downloads for that day. One row is inserted each day for each id combination, and the index spans all of the ids and the date.
I have found through testing that it is quicker to perform two queries to get the exact row I want under certain circumstances. I would like a second opinion about this.
Here is a scenario that is very fast and uses the index:
SELECT * FROM foo WHERE A = 1 AND B = 1 AND mydate BETWEEN 123456789 AND 134567890 ORDER BY mydate DESC LIMIT 1
(The index is A, B, mydate)
Here is one that is very slow and doesn't use the index:
SELECT * FROM foo WHERE A IN (1, 2) AND B = 1 AND mydate BETWEEN 123456789 AND 134567890 GROUP BY A, B ORDER BY mydate DESC
This returns the correct result but doesn't use the index and is very slow. In reality, this simple example might use the index, but something like A IN(1,2,3,4,5,6,7,8,....10000) AND B IN (1,2,3,4,5,... 10000) doesn't, and that's what I need to cater for.
Here is where it gets interesting.
The following uses the index and is very fast:
SELECT *, MAX(mydate) FROM foo WHERE A IN (1,2,3,4,5,6,7,8,....10000) AND B IN (1,2,3,4,5,6,7,8,....10000) AND mydate BETWEEN 123456789 AND 134567890 GROUP BY A, B
The rows returned contain each unique combination of ids and the MAX of mydate for each combination. But, the row returned for each combination isn't necessarily the one with the corresponding MAX(mydate), and therefore does not necessarily give the correct downloads of that day. The MAX value is the correct value for that specific combination though, so my second query can be specific and use the index. Assuming A was 1, B was 1 and the MAX(mydate) equalled 1235555555 for that specific id combination, then I can execute
SELECT * FROM foo WHERE A = 1 AND B = 1 AND mydate = 1235555555
This second query returns the specific row I want, uses the index and is therefore fast.
I do have to do a foreach with php, so there's a processing overhead there, but it's still significantly quicker than trying to get MySQL to do all the work.
Another benefit is that all of these simple queries execute as seperate MySQL processes.
It just doesn't feel right, am I missing something?

Order By on date field starting in a middle point of the dates range

I have a table "A" with a "date" field. I want to make a select query and order the rows with previous dates in a descending order, and then, the rows with next dates in ascending order, all in the same query. Is it possible?
For example, table "A":
id date
---------------------
a march-20
b march-21
c march-22
d march-23
e march-24
I'd like to get, having as a starting date "march-22", this result:
id date
---------------------
c march-22
b march-21
a march-20
d march-23
e march-24
In one query, because I'm doing it with two of them and it's slow, because the only difference is the sorting, and the joins I have to do are a bit "heavy".
Thanks a lot.
You could use something like this -
SELECT *
FROM test
ORDER BY IF(
date <= '2012-03-22',
DATEDIFF('2000-01-01', date),
DATEDIFF(date, '2000-01-01')
);
Here is a link to a test on SQL Fiddle - http://sqlfiddle.com/#!2/31a3f/13
That's wrong, sorry :(
From documentation:
However, use of ORDER BY for individual SELECT statements implies nothing about the order in which the rows appear in the final result because UNION by default produces an unordered set of rows. Therefore, the use of ORDER BY in this context is typically in conjunction with LIMIT, so that it is used to determine the subset of the selected rows to retrieve for the SELECT, even though it does not necessarily affect the order of those rows in the final UNION result. If ORDER BY appears without LIMIT in a SELECT, it is optimized away because it will have no effect anyway.
This should do the trick. I'm not 100% sure about adding an order in a UNION...
SELECT * FROM A where date <= now() ORDER BY date DESC
UNION SELECT * FROM A where date > now() ORDER BY date ASC
I think the real question here is how to do the joining once. Create a temporary table with the result of joining, and make the 2 selects from that table. So it will be be time consuming only on creation (once) not on select query (twice).
CREATE TABLE tmp SELECT ... JOIN -- do the heavy duty here
With this you can make the two select statenets as you originally did.

SQL Server: Selecting DateTime and grouping by Date

This simple SQL problem is giving me a very hard time. Either because I'm seeing the problem the wrong way or because I'm not that familiar with SQL. Or both.
What I'm trying to do: I have a table with several columns and I only need two of them: the datetime when the entry was created and the id of the entry. Note that the hours/minutes/seconds part is important here.
However, I want to group my selection according to the DATE part only. Otherwise all groups will most likely have 1 element.
Here's my query:
SELECT MyDate as DateCr, COUNT(Id) as Occur
FROM MyTable tb WITH(NOLOCK)
GROUP BY CAST(tb.MyDate as Date)
ORDER BY DateCr ASC
However I get the following error from it:
Column "MyTable.MyDate" is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
If I don't do the cast in the GROUP BY, everything fine. If I cast MyDate to DATE in the SELECT and keep the CAST from GROUP BY, everything fine once more. Apparently it wants to keep the same DATE or DATETIME format in the GROUP BY as in the SELECT.
My approach can be completely wrong so I am not necessarily looking to fix the above query, but to find the proper way to do it.
LE: I get the above error on line 1.
LE2: On a second look, my question indeed is not very explicit. You can ignore the above approach if it is completely wrong. Below is a sample scenario
Let me tell you what I need: I want to retrieve (1) the DateTime when each entry was created. So if I have 20 entries, then I want to get 20 DateTimes. Then if I have multiple entries created on the same DAY, I want the number of those entries. For example, let's say I created 3 entries on Monday, 1 on Tuesday and 2 today. Then from my table I need the datetimes of these 6 entries + the number of entries which were created on each day (3 for 19/03/2012, 1 for 20/03/2012 and 2 for 21/03/2012).
I'm not sure why you're objecting to performing the CONVERT in both the SELECT and the GROUP BY. This seems like a perfectly logical way to do this:
SELECT
DateCr = CONVERT(DATE, MyDate),
Occur = COUNT(Id)
FROM dbo.MyTable
GROUP BY CONVERT(DATE, MyDate)
ORDER BY DateCr;
If you want to keep the time portion of MyDate in the SELECT list, why are you bothering to group? Or how do you expect the results to look? You'll have a row for every individual date/time value, where the grouping seems to indicate you want a row for each day. Maybe you could clarify what you want with some sample data and example desired results.
Also, why are you using NOLOCK? Are you willing to trade accuracy for a haphazard turbo button?
EDIT adding a version for the mixed requirements:
;WITH d(DateCr,d,Id) AS
(
SELECT MyDate, d = CONVERT(DATE, MyDate), Id
FROM dbo.MyTable)
SELECT DateCr, Occur = (SELECT COUNT(Id) FROM d AS d2 WHERE d2.d = d.d)
FROM d
ORDER BY DateCr;
Even though this is an old post, I thought I would answer it. The solution below will work with SQL Server 2008 and above. It uses the over clause, so that the individual lines will be returned, but will also count the rows grouped by the date (without time).
SELECT MyDate as DateCr,
COUNT(Id) OVER(PARTITION BY CAST(tb.MyDate as Date)) as Occur
FROM MyTable tb WITH(NOLOCK)
ORDER BY DateCr ASC
Darren White

Finding in which category the days falls in the Given Category of table in SQL

I have a table with column as and its value as given
ProvisionType------From Days------ToDays
goodLoan --------- 1------------------90
Substand ------------91--------------180
doubful--------------181--------------365
bad----------------365----------------365+
IN the following case i may have a variable which may be different and i am managing that from code....But suppose if i want to find where exactly 200 falls between From days and To Days so i get the Correct Provision Type. So please anybody could help me on this
If you're using SQL Server then this should work. Not sure if MySql has BETWEEN...
SELECT ProvisionType
FROM myTable
WHERE (myVariable BETWEEN FromDays AND ToDays)
It could also be written without the BETWEEN...
SELECT ProvisionType
FROM myTable
WHERE myVariable >= FromDays
AND myVariable <= ToDays
For this to work you should replace 365+ on the last provision with an actual number, otherwise the ToDays field will need to be a varchar field rather than numeric. Also, if a value of 365 is provided, would it be expected to fall into the last category or the one before it? The other categories have a distinct cut-off point, but the last ones overlap.
Does this work (in SQL Server):
select top 1 ProvisionType
from table
where FromDays < 200
order by FromDays desc
For MySQL:
select ProvisionType
from table
where FromDays < 200
order by FromDays desc
limit 1
I'm not sure why you need both FromDays and ToDays. That seems like you're asking for overlaps and gaps. If you just have FromDays, you guarantee no gaps or overlaps and you don't have to do clever things to manage the highest limit, ie. 365+ days.

Order a query with two keys SQL Server 2008

I am trying to order a query by two keys. The query is built with several subqueries. The table contains, beside columns with other data, two columns, Key and Key_Father. So I need to order the results since SQL to print the results in a report. This is an example:
Key Key_Father
4 NULL
1 4
2 4
7 NULL
1 7
2 7
As you can see is a structure father-son, where a row is a father if the Key_Father is NULL and the Key column start from one for each son with a different father.
The first subquery gives the data in order, because is stored on that order in the table, but the second subquery that uses a group by, no. So I tried adding a extra column with Row_Number on the first subquery to keep that order, but the second subquery does the same thing.
This is the query:
SELECT Orden,INV_Key,Key_Padre,INV.INV_ID,INV.BOD_Bodega_ID,
CASE WHEN MAX(HIS_Ventas) > 0 OR max(HIS_Disponible) > 0 THEN 1 ELSE 0 END AS Participacion,MAX(ISNULL(HIS_Ventas,0)) AS Ventas
FROM(SELECT ROW_NUMBER() OVER (ORDER BY C.INV_Compra_ID) Orden,C.BOD_Bodega_ID,INV_Key,Key_Padre,CD.INV_ID
FROM dbo.INV_COMPRAS_USADOS C
INNER JOIN dbo.INV_COMPRAS_USADOS_DET CD ON C.INV_Compra_ID = CD.INV_Compra_ID
WHERE C.INV_Compra_ID = #Compra_ID
AND ((Key_Padre IS NULL AND CD.INV_Catalogo_Codigo = ISNULL(#Cod_Catalogo,CD.INV_Catalogo_Codigo)
AND INV_Key IN (SELECT DISTINCT Key_Padre
FROM dbo.INV_COMPRAS_USADOS_DET
WHERE INV_Compra_ID = #Compra_ID AND Key_Padre IS NOT NULL))
OR Key_Padre IN (SELECT DISTINCT INV_Key
FROM dbo.INV_COMPRAS_USADOS_DET
WHERE INV_Compra_ID = #Compra_ID AND (Key_Padre IS NULL AND CD.INV_Catalogo_Codigo = ISNULL(#Cod_Catalogo,CD.INV_Catalogo_Codigo))))) INV
LEFT JOIN DBO.HIS_HISTORICO_DETALLE HD ON INV.INV_ID = HD.INV_ID AND HD.BOD_Bodega_ID = INV.BOD_Bodega_ID
LEFT JOIN DBO.HIS_HISTORICO_INVENTARIO H on H.HIS_Historico_ID= HD.HIS_Historico_ID AND (CONVERT(datetime,(convert(varchar(20),HIS_Historico_Ano) + '/' + convert(varchar(20),HIS_Historico_Mes) + '/01')) BETWEEN #FechaDesde AND #FechaHasta)
WHERE H.HIS_Historico_Mes IS NOT NULL OR INV.INV_ID IS NULL
GROUP BY Orden,INV_Key,Key_Padre,INV.INV_ID,INV.BOD_Bodega_ID,HIS_Historico_Ano,HIS_Historico_Mes
Another interesting thing (well for me) is that when I change the #Variables for Constant values, the second query keeps the correct order, even when the constant values are the same that the #variables. This is just a portion of the total query, is a subquery that needs of another two selects, and I need to keep the order from those selects too.
So I hope that someone could help me with this. Thanks!
To order the results you need to place an ORDER BY clause on the outermost SELECT statement. Using ORDER BY in a nested SELECT is generally not permitted but even if you work around it (e.g. by using TOP), you can't rely on the results being ordered in any particular way.
Without an ORDER BY the results may appear to be coming out in the order you want but this cannot be relied upon. Running the same query on a different server or at some point in the future may produce a different order where differences in statistics, server load, etc can affect how the query optimizer actually executes the statement.
The portion of the query you've provided is outputting the following columns. Which are the ones you want to order by?
Orden (although this is just an alias for INV_Compra_ID as far as orderin is concerned)
INV_Key
Key_Padre
INV_ID
BOD_Bodega_ID
Participacion
Ventas
Let's say you want to order by just thre of them, then you need to append the following clause to the outermost SELECT:
ORDER BY
Orden,
INV_Key,
Key_Padre,
This should do it. I'm not sure if I'm missing an obvious simplification though.
ORDER BY ISNULL(Key_Father,[Key]), ISNULL(Key_Father,-1),[Key]