I have column which has values like this
"BEAAL - Aalter - Belgium - EMEA"
I want to create a table where I want to split it in to multiple columns
Location = BEAAL - Aalter
Country = Belgium
Region = EMEA
So my table should look like this
'ID' 'Text' 'Location' 'Country' 'Region'
'1 ' 'BEAAL - Aalter' 'BEAAL - Aalter' 'Belgium' 'EMEA'
How can this be achieved in SQL Server 2008? I have around 1000 entries in table to split this way.
This script produces what you want, using a slightly modified version of the SplitStrings function you can find in this answer. All credit to Aaron Bertrand for that function.
Modified SplitStrings function:
CREATE FUNCTION [dbo].[SplitStrings](#List NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN ( SELECT Item=LTRIM(RTRIM(Item)),Id FROM
( SELECT Item = x.i.value('(./text())[1]', 'nvarchar(max)'),Id=x.i.value('for $i in . return count(../*[.<<$i])+1','INT')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(#List, '-', '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
The script:
DECLARE #t TABLE(id int identity(1,1), blabla VARCHAR(512));
INSERT INTO #t(blabla)VALUES('BEAAL - Aalter - Belgium - EMEA');
INSERT INTO #t(blabla)VALUES('YYYY - Gent - Belgium - XXXX');
INSERT INTO #t(blabla)VALUES('ZZZZZ - Brussel - Belgium - WWWWW');
SELECT
t.id,
Location=MAX(CASE WHEN split.Id=1 THEN split.Item END)+' - '+MAX(CASE WHEN split.Id=2 THEN split.Item END),
Country=MAX(CASE WHEN split.Id=3 THEN split.Item END),
Region=MAX(CASE WHEN split.Id=4 THEN split.Item END)
FROM
#t AS t
CROSS APPLY dbo.SplitStrings(blabla) AS split
GROUP BY
t.Id;
The result:
╔════╦═════════════════╦═════════╦════════╗
║ id ║ Location ║ Country ║ Region ║
╠════╬═════════════════╬═════════╬════════╣
║ 1 ║ BEAAL - Aalter ║ Belgium ║ EMEA ║
║ 2 ║ YYYY - Gent ║ Belgium ║ XXXX ║
║ 3 ║ ZZZZZ - Brussel ║ Belgium ║ WWWWW ║
╚════╩═════════════════╩═════════╩════════╝
Related
I'm trying to get from an decimal(13.6) value to currency in EURO's
I'm getting this as result right now:
╔══════════════╦═════════╗
║ total ║ Date ║
╠══════════════╬═════════╣
║8887616.500000║ 2017 ║
╚══════════════╩═════════╝
What I want is something like this one:
╔══════════════╦═════════╗
║ total ║ Date ║
╠══════════════╬═════════╣
║€8,887.616.50 ║ 2017 ║
╚══════════════╩═════════╝
Or this one:
╔══════════════╦═════════╗
║ total ║ Date ║
╠══════════════╬═════════╣
║ €M8,9 ║ 2017 ║
╚══════════════╩═════════╝
I did try to convert from decimal but had no luck with that
SELECT SUM(totalExcl) AS total, DATE_FORMAT(date_add, '%Y') AS 'Date'
FROM ex.ps_oxo_quotation
WHERE saleType IN ('IEW' , 'As', 'Pr')
AND date_add >= '2017-01-01 00:00:00'
GROUP BY 'Date'
ORDER BY 'Date' DESC
This will give you a sum formatted in Euro:
SELECT CONCAT('€', FORMAT(SUM(totalExcl), 2, 'de_DE')) AS total
Will show: €8.890.905,86
The other requested alternative:
SELECT CONCAT('€M', FORMAT((SUM(totalExcl)/1000000), 1, 'de_DE')) AS total
Will show: €M8,9
Note that this example will show the sum according to standards (LOCALE de_DE), and not with the exact format you have requested, that have mixed dots "." and commas "," in a non standard way. This could easily be fixed with some string manipulation if you really must format the sum that way.
I have a table whose structure is as follows
╔════════╦══════════╦════════════╗
║ app_id ║ app_name ║ categoryId ║
╠════════╬══════════╬════════════╣
║ 1200 ║ A ║ B ║
║ 1200 ║ A ║ C ║
║ 1200 ║ A ║ D ║
║ 1201 ║ E ║ F ║
║ 1201 ║ E ║ G ║
╚════════╩══════════╩════════════╝
Now I have 1600 such data. What I am trying to get is, a query to fetch data till the number of distinct appids reaches 200. After 200 is reached it should no longer fetch the rest of the data. I tried count(distinct(app_id)) but that doesn't seem to work the way I think. I am really struck here and it is a major performance issue. Any help is much appreciated. Thanks in advance.
You can try like this:
SELECT app_id
FROM myTable
GROUP BY app_id
HAVING COUNT(distinct app_id) < 200;
If what you want is
a query to fetch data till the number of distinct appids reaches 200
then you can use variables to implement this:
SELECT app_id, app_name, categoryId
FROM (
SELECT app_id, app_name, categoryId,
#appIDcnt := IF (#appID = app_id,
IF(#appID := app_id, #appIDcnt, #appIDcnt),
IF(#appID := app_id, #appIDcnt+1, #appIDcnt+1)) AS cnt
FROM mytable
CROSS JOIN (SELECT #appID := 0, #appIDcnt := 0) AS vars
ORDER BY app_id ) AS t
WHERE t.cnt <= 200
In the above query #appIDcnt variable is used to count distinct app_id values. The query fetches table data until #appIDcnt value reaches 200.
Demo here
use limit it will return the first 200 results only.
SELECT DISTINCT ap_id FROM appTable LIMIT 200
and then if you need to get the next 200 then use offset 200 which will start with row 201
SELECT DISTINCT ap_id FROM ap_Table LIMIT 200 OFFSET 200
I have a table similar to
╔═════════════════════════════════════╗
║ id type report_id state ║
╠═════════════════════════════════════╣
║ 1 dc 122 pending ║
║ 2 dc 123 pending ║
║ 3 dc 123 approved ║
║ 4 dc 123 pending ║
║ 5 dc 123 approved ║
║ 6 bb 123 pending ║
║ 7 dc 123 pending ║
║ 8 dc 124 pending ║
║ 9 dc 125 pending ║
╚═════════════════════════════════════╝
I am trying to fetch the last report_id by type where state is pending
so results I would want are
122 (id 1 -- dc)
123 (id 6 -- bb)
123 (id 7 -- dc)
124 (id 8 -- dc)
125 (id 9 -- dc)
Right now I am fetching all, then running 3 loops on the array... I know there is a way to either join or perform an outer query to get it without the loops, any input on how i would word it?
I ran a query on a test database (15 records) and it worked there, but hangs on the live database (40k records)
SELECT report_id, type, state
FROM histories
WHERE id IN (
SELECT MAX(id) FROM histories
GROUP BY report_id
)
AND state <> 'approved'
For this, the sub-query executes fine and gives me proper results, the main query will give me results if I extract the sub-query, but combine them and it hangs...
Tested on ta SQL (not MySQL) database on a local machine with a limited data-set
I think you just want a group by with a filter:
select report_id, type, max(id)
from table t
where state = 'pending'
group by report_id, type;
Something like
SELECT report_id, MAX(id), type
FROM table_name
WHERE state = 'pending'
GROUP BY report_id, type
ORDER BY report_id
where table_name is your tables name. It is difficult to tell what you want from the results in your question.
What I did was this
take the sub-query and run it
SELECT MAX(id) FROM histories
GROUP BY report_id
... store as $id_array
then take the result and store it as CSV
$id_csv = implode(', ' $id_array);
then run my primary query
SELECT report_id, type, state
FROM histories
WHERE id IN ($id_csv)
AND state <> 'approved'
Not sure why it made a difference separating it, but it did the job (query takes about 3 seconds to run, I wish it were faster)
i have two tables for example:
BALANCE VS
╔══════╦══════╗ ╔══════╦═══════╗
║ V_ID ║ BAL ║ ║ V_ID ║ NAME ║
╠══════╬══════╣ ╠══════╬═══════╣
║ 1 ║ 1000 ║ ║ 1 ║ Carl ║
║ 1 ║ 500 ║ ║ 2 ║ Peter ║
║ 1 ║ -200 ║ ╚══════╩═══════╝
║ 2 ║ 350 ║
║ 2 ║ 1000 ║
╚══════╩══════╝
Now i've done a query like:
select
NAME,sum(BAL)
from VS,BALANCE
where VS.V_ID = BALANCE.V_ID
group by NAME
And the result is:
╔═══════╦══════╗
║ NAME ║ BAL ║
╠═══════╬══════╣
║ Carl ║ 1300 ║
║ Peter ║ 1350 ║
╚═══════╩══════╝
But i'd like to know how its done without the ´group by´ clause. Something like a subquery.
I tried different things but i cant figure out how it would work. I always end with results like all the values summed up into one row or results like the above one but without grouping.
may be anyone could help me
greetings
edit:forgot sum()
To get your current SQL to work using GROUP BY you would need the following (ie the SUM aggregate function):-
select NAME, SUM(BAL)
from VS, BALANCE
WHERE VS.V_ID = BALANCE.V_ID
group by NAME
Note that this is just your original SQL minimally modified to work and it still uses the implicit join you coded. Implicit joins should generally be avoided and better to use explicit INNER JOIN....ON syntax:-
select NAME, SUM(BAL)
from VS
INNER JOIN BALANCE
ON VS.V_ID = BALANCE.V_ID
group by NAME
If you really want to avoid the GROUP BY then it is possible using a sub query, but is likely to be slower (as it effectively has to perform an extra query for every row tha main query returns):-
select NAME, (SELECT SUM(BAL) FROM BALANCE WHERE BALANCE.V_ID = VS.V_ID)
from VS
EDIT, in response to your comment on sub queries.
Correlated sub queries effectively force MySQL to get a result set, and then for each row on the result set to perform another query. Most of the time they are used to get an aggregate value (such as the max value of a field related to a row on the returned row, but where GROUP BY on the main query would not be viable).
For example if you had a list of comments for a user, but on each row you wanted to know the date of the latest comment from that user you might do the following:-
SELECT users.user_name, comments.comment_date, (SELECT MAX(comment_date) FROM comments WHERE comments.user_id = users.id) AS latest_comment_date
FROM users
INNER JOIN comments
ON users.id = comments.user_id
This could be written to do a non correlated sub query using GROUP BY which is then joined:-
SELECT users.user_name, comments.comment_date, latest_comment_date
FROM users
INNER JOIN comments
ON users.id = comments.user_id
INNER JOIN
(
SELECT user_id, MAX(comment_date) AS latest_comment_date
FROM comments
GROUP BY user_id
) sub1
ON users.id = sub1.user_id
If you are dealing with a large number of records on users this would likely be faster.
However if you were only dealing with a tiny number of records on users (and determining that number was quite complex), getting ALL the max comment dates would be an unnecessary overhead, and it forces a join against a sub query which isn't likely to use indexes.
Try joining tables:
select NAME,BAL from VS JOIN BALANCE ON VS.V_ID = BALANCE.V_ID
Will return
NAME | BAL
-------------
Carl | 1000
Carl | 500
Carl | -200
Peter| 350
Peter| 1000
To get sum of BAL, you have to use GROUP BY, otherwise you will get SUM of all rows
I work with mysql and I've never encountered such a great challenge.
I hope you can help..
I have 1 table called Reports:
ID SerialNumber Remain_Toner_Black
7099 Z5UEBJAC900002Y 37
7281 Z5UEBJAC900002Y 36
7331 Z5UEBJAC900002Y 100
7627 8Z37B1DQ100105N 58
7660 8Z37B1DQ100105N 57
5996 CND8DDM2FH 83
5971 CND8DDM2FH 83
7062 3960125290 0
7088 3960125290 93
7100 3960125290 100
Now I want to be able to select records from the table where Remain_Toner_Black is higher than Remain_Toner_Black of the previous row in the table with the same SerialNumber (by previous I mean lower ID with the same SerialNumber).
For the above records I want the results below:
ID SerialNumber Remain_Toner_Black_Before Remain_Toner_Black_After
7331 Z5UEBJAC900002Y 36 100
7088 3960125290 0 93
7100 3960125290 93 100
SELECT a.ID, a.SerialNumber,
b.Remain_Toner_Black BeforeCount,
a.Remain_Toner_Black AfterCount
FROM
(
SELECT A.ID,
A.SerialNumber,
A.Remain_Toner_Black,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.SerialNumber = a.SerialNumber AND
c.ID <= a.ID) AS RowNumber
FROM TableName a
) a
INNER JOIN
(
SELECT A.ID,
A.SerialNumber,
A.Remain_Toner_Black,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.SerialNumber = a.SerialNumber AND
c.ID <= a.ID) AS RowNumber
FROM TableName a
) b ON a.SerialNumber = b.SerialNumber AND
a.RowNumber = b.RowNumber + 1
WHERE b.Remain_Toner_Black < a.Remain_Toner_Black
SQLFiddle Demo
OUTPUT
╔══════╦═════════════════╦═════════════╦════════════╗
║ ID ║ SERIALNUMBER ║ BEFORECOUNT ║ AFTERCOUNT ║
╠══════╬═════════════════╬═════════════╬════════════╣
║ 7331 ║ Z5UEBJAC900002Y ║ 36 ║ 100 ║
║ 7088 ║ 3960125290 ║ 0 ║ 93 ║
║ 7100 ║ 3960125290 ║ 93 ║ 100 ║
╚══════╩═════════════════╩═════════════╩════════════╝
BRIEF EXPLANATION
What the query above does is it generates a sequential number which mimics ROW_NUMBER() on other RDBS for every SerialNumber ordered by ID in ascending order.
The two subquery is then joined via the SerialNumber and sequential number generated. On the generated number, the value on the first subquery must be equal to plus one of the value on the second subquery to get the number of toner on the next reord.
MySQL (or indeed most other RDBMS) doesn't easily allow cross-row comparisons.
To do this sort of query, you must either perform a very expensive join comparing one version of the table to several rows of another version of the table, or construct a complex expression using user variables.
For example (with user variables):
SELECT ID, SerialNumber, #x Remain_Toner_Before,
#x := Remain_Toner_Black AS Remain_Toner_After
FROM Reports, (SELECT #x := -4) x
WHERE Remain_Toner_Black > #x
AND SerialNumber = '3960125290'
ORDER BY ID;
(the -4 is from your comment to another answer)
A better solution is to do this with cursors or in your application code, where you need only do one pass and compare simple logic by using variables in the cursor or application code.