I have a couple of tables that I'd like to combine into one list. I have limited knowledge of what I can do with MySQL and already hit the fact that UNION needs to have the same amount of columns...
One table has data like the following:
batch_no
1
2
3
4
5
6
9
10
12
The other has
batch_no
subbatch_no
7
1
7
2
7
3
8
1
8
2
11
1
11
2
I basically want to be able to have a output that displays like this:
batch_no
1
2
3
4
5
6
7-1
7-2
7-3
8-1
8-2
9
10
11-1
11-2
12
I've had various attempts but the following is the best I came up with but obviously is sorting incorrectly...
SELECT batch_no FROM batch
UNION
SELECT CONCAT(batch_no,'-',subbatch_no) FROM subbatch
ORDER BY batch_no DESC
With this the order is seemingly being done as if it were text because I have put the hyphen in, stumped as to how to do this.
Do the ordering on the original union, adding an extra subbatch_no column to the batch subquery. Then order these together by two columns in the main query, where you can also concatenate them with the - separator.
SELECT CONCAT_WS('-', batch_no, subbatch_no) AS combined_batch_no
FROM (
SELECT batch_no, NULL AS subbatch_no
FROM batch
UNION
SELECT batch_no, subbatch_no
FROM subbatch
) AS sub1
ORDER by batch_no, subbatch_no
it is actually quite easy sorting apha numrical qith your data
SELECT CAST(batch_no as char) batchno FROM batch
UNION
SELECT CONCAT(batch_no,'-',subbatch_no) FROM subbatch
ORDER BY batchno+0 ASC
| batchno |
| :------ |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7-1 |
| 7-2 |
| 7-3 |
| 8-1 |
| 8-2 |
| 9 |
| 10 |
| 11-1 |
| 11-2 |
| 12 |
db<>fiddle here
select CONCAT_WS('-',batch_no,subbatch_no) from (
SELECT batch_no,null subbatch_no FROM batch
UNION ALL
SELECT batch_no,subbatch_no FROM subbatch
) A
ORDER BY batch_no,subbatch_no
Try with the following:
WITH cte AS (
SELECT batch_no, NULL as subbatch_no FROM tab1
UNION ALL
SELECT * FROM tab2
)
SELECT CONCAT_WS('-' , batch_no, subbatch_no) AS batch_no
FROM cte
ORDER BY cte.batch_no, cte.subbatch_no
Check the demo here.
Related
I need query:
for example: '1','2','9','10','3','4','5','6','7','8';
table name:getstdata
ID
1
2
3
4
5
5
7
Query:
select ID from getstdata where ID in('1','2','9','10','3','4','5','6','7','8')
Results:
'1','2','3','4','5','6','7'
In above data 8,9,10 not in data. I need that not available Data. Please give me solution for it.
Thank you
What Akina meant was to create a temp table from a query since you don't have an existing table that stores all info (what my ignored question in comment suggest).
So you have table getstdata and you want to get an example of number range from 1 to 10 that doesn't exist in the table ID column, then you make a temp table that stores a range of 1 to 10 numbers like this:
SELECT 1 AS T UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION
SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10;
Which will give you this result:
+-----+
| T |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+-----+
Then you make that as a sub-query and do a LEFT JOIN to your getstdata table like this:
SELECT * FROM
(SELECT 1 AS T UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION
SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) A
LEFT JOIN getstdata B ON A.T=B.ID;
That will give you something like this:
+-----+------+
| T | ID |
+-----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | NULL |
| 9 | NULL |
| 10 | NULL |
+-----+------+
In the above result, the NULL value is what you're looking for. Therefore you can refine the query to become like this:
SELECT A.T FROM
(SELECT 1 AS T UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION
SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) A
LEFT JOIN getstdata B ON A.T=B.ID
WHERE B.ID IS NULL;
This end result:
+-----+
| T |
+-----+
| 8 |
| 9 |
| 10 |
+-----+
As you can see, that's a quick way to solve your current issue but what if the comparison that you're making is not numbers? of what if the numbers range from 1-1000? Would you rather to write SELECT 1 UNION SELECT 2 UNION ... all the way to ... SELECT 999 UNION SELECT 1000; as the sub-query? But if you're using MariaDB version 10.0.3 and above, you can easily make a range of numbers using it's built-in sequence engine.
*A quick MariaDB example using sequence engine:
SELECT A.T FROM
(SELECT Seq AS T FROM seq_1_to_10) A
LEFT JOIN getstdata B ON A.T=B.ID
WHERE B.ID IS NULL;
Still, that's just a solution to compare numbers only. Fiddle here.
My database is like
id|service_id
1 | 8
2 | 3
3 | 4
4 | 1
5 | 3
6 | 2
7 | 1
i want to sort it like rows with same service_id came together but randomly. like
id|service_id
1 | 8
4 | 1
7 | 1
2 | 3
5 | 3
6 | 2
3 | 4
means first all rows sort via service_id then again sort via random service_id. I have tried SELECT * from sample_table order by service_id DESC and tried ASC too but it only do sort via DESC or ASC. I have tried order by rand(service_id) too but it is also showing some fixed sorting.
select t.*
from your_table t
join
(
select service_id, rand() as r
from your_table
group by service_id
) tmp on t.service_id = tmp.service_id
order by tmp.r;
SQLFiddle demo
Basically this makes a random substitute for the service_id and orders by that
I have a report made in report builder 3 that will find order lines based off of an order number. I am trying to have the row repeat based on the quantity value of that row like this:
Part Qty
001 5
002 2
I am trying to get it to repeat the 001 row 5 times and the 002 row 2 times.
(This is for printing off labels)
I cannot create or update tables in the database.
Thanks
This can be addressed in the underlying SQL statement. See this answer.
The basic idea is to create a view with a list of numbers (N). Then join to that view with N <= Qty:
CREATE VIEW [dbo].[vwNumbers]
AS
SELECT N=1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5
UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10
UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 26 UNION ALL SELECT 27 UNION ALL SELECT 28 UNION ALL SELECT 29 UNION ALL SELECT 20
UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23 UNION ALL SELECT 24 UNION ALL SELECT 25
UNION ALL SELECT 26 UNION ALL SELECT 27 UNION ALL SELECT 28 UNION ALL SELECT 29 UNION ALL SELECT 30
GO
SELECT Part
FROM PartList
INNER JOIN vwNumbers ON N <= Qty
I have the same problem and after searching a lot I could do it this way, I have to repeat and display a product label based on a number, for example in my table label that I have:
ItemId | Barcode | CustName | LabelQty
001 | 123abc | Jhon | 3
So in this case I need to repeat the same label 3 times.
I achieved this by grouping the table by a value that count the number of times to be repeated.
ItemId | Barcode | CustName | LabelQty | Counter
001 | 123abc | Jhon | 3 | 1
001 | 123abc | Jhon | 3 | 2
001 | 123abc | Jhon | 3 | 3
In my case the 3 labels are the same so I fill only the first row with label data in order to reduce the data to process, like this:
ItemId | Barcode | CustName | LabelQty | Counter
001 | 123abc | Jhon | 3 | 1
null | null | null | null | 2
null | null | null | null | 3
in the field expresion I use =first(field.value, 'datasource') to find the row with data.
if you have to repeat different values I suppose that you have to fill all rows.
hope this helps.
sorry for bad english.
I have a table that stores the amount of errors according to what alarm-id it is. The table looks something like this:
|----DATE----|---ALARM_ID---|---COUNTER---|
| 2012-01-01 | 1 | 32 |
| 2012-01-01 | 2 | 28 |
| 2012-01-02 | 1 | 12 |
| 2012-01-02 | 2 | 23 |
| 2012-01-03 | 1 | 3 |
| 2012-01-03 | 2 | 9 |
| 2012-01-05 | 1 | 8 |
| 2012-01-05 | 2 | 1 |
| 2012-01-07 | 1 | 102 |
| 2012-01-07 | 2 | 78 |
Notice the gap between date (2012-01-03 - 2012-01-05) and (2012-01-05 - 2012-01-07). On these dates there isn't any data because the system, that my program is monitoring, haven't reported any errors at that date. What I'm looking for is a SQL SELECT query that returns the total amount of errors on each date, for example:
|----DATE----|---COUNTER---|
| 2012-01-01 | 60 |
| 2012-01-02 | 35 |
| 2012-01-03 | 12 |
| 2012-01-04 | 0 |
| 2012-01-05 | 9 |
| 2012-01-06 | 0 |
| 2012-01-07 | 180 |
I have a query that returns ID's even if they doesn't exist in the table, and if the ID doesn't exist, return the ID anyway with the COUNTER value 0. As such:
BEFORE AFTER
|---ID---|---COUNTER---| |---ID---|---COUNTER---|
| 1 | 2 | | 1 | 2 |
| 2 | 6 | | 2 | 6 |
| 3 | 1 | --> | 3 | 1 |
| 5 | 9 | | 4 | 0 |
| 6 | 10 | | 5 | 9 |
| 6 | 10 |
| 7 | 0 |
| 8 | 0 |
The query goes like this:
select t.num as ID, coalesce(yt.COUNTER, 0)
from all_stats yt right join
( select t1.num + t2.num * 10 + t3.num * 100 + t4.num * 1000 as num
from ( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t1 cross join
( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t2 cross join
( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t3 cross join
( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t4 )
t on yt.ID = t.num
where (t.num between (select min(ID) from all_stats) and (select max(ID) from all_stats)) order by ID
I can't figure out how I can change this query when it's regarding dates. Can someone please help me on this issue?
I'm using MySQL
Thanks in advance, Steve-O
The exact details will depend on the DBMS, and on the nature of the database (e.g., OLAP-oriented vs. OLTP-oriented), but one common general approach is to create an auxiliary calendar table that represents dates as a dimension. Then you can use regular JOINs, rather than having to use complex logic to generate missing dates.
The answers to this StackOverflow question describe how to apply this approach on MySQL.
You can use a similar approach for numbers, by the way, by having a numbers tables; I've never done that myself for numbers, but it seems to be a popular idea; see this dba.stackexchange.com question.
If you're using SQL Server 2005 or above you can use a CTE (if not, a loop or other sql technique to populate a table with the dates in the range). Note also there is a limit to the levels of recursion within a CTE.
declare #dateRange table
(
dateBegin datetime,
dateEnd datetime
)
insert into #dateRange (dateBegin, dateEnd)
values ('2012-01-01', '2012-01-07')
;with cte (d)
as (select dateBegin as d
from #dateRange tbl
where datediff(day, tbl.dateBegin, tbl.dateEnd) <= 100
union all
select dateadd(day, 1, cte.d) as d
from cte
inner join #dateRange tbl on cte.d < tbl.dateEnd)
Then get the full results either using the CTE or a temporary table that contains the set of dates in the range:
select cte.d, sum(isnull(e.errorCounter, 0))
from cte
left outer join #errors e on e.errorDate = cte.d
group by cte.d
order by cte.d
You really should handle this at the application layer (ie iterate over the known date range and pull the non-zero vals from the resultset) or fix your table to always include the dates needed if you MUST have a database-centered solution. There's no really good way to generate, on the fly, a set of dates to use in building a continuous date range query.
You can see this for some examples of DB scripting solutions:
Return temp table of continuous dates
But I think you're posing the wrong question. Fix the database to include what you need, or fix how you're generating your report. Databases aren't meant to do interpolation and data generation.
I want to calculate the difference in unique date fields between different rows in the same table.
For instance, given the following data:
id | date
---+------------
1 | 2011-01-01
2 | 2011-01-02
3 | 2011-01-15
4 | 2011-01-20
5 | 2011-01-10
6 | 2011-01-30
7 | 2011-01-03
I would like to generate a query that produces the following:
id | date | days_since_last
---+------------+-----------------
1 | 2011-01-01 |
2 | 2011-01-02 | 1
7 | 2011-01-03 | 1
5 | 2011-01-10 | 7
3 | 2011-01-15 | 5
4 | 2011-01-20 | 5
6 | 2011-01-30 | 10
Any suggestions for what date functions I would use in MySQL, or is there a subselect that would do this?
(Of course, I don't mind putting WHERE date > '2011-01-01' to ignore the first row.)
A correlated subquery could be of help:
SELECT
id,
date,
DATEDIFF(
(SELECT MAX(date) FROM atable WHERE date < t.date),
date
) AS days_since_last
FROM atable AS t
Something like this should work :
SELECT mytable.id, mytable.date, DATEDIFF(mytable.date, t2.date)
FROM mytable
LEFT JOIN mytable AS t2 ON t2.id = table.id - 1
However, this imply that your id are continuous in your table, otherwise this won't work at all. And maybe MySQL will complain for the first row since t2.date will be null but I don't have the time to check now.