Convert Excel Rows Into SQL Columns - mysql

I have a client that inherited an Excel spreadsheet full of contact information for a mailing list. Apparently, his predecessor attempted to format the spreadsheet for printing pin-feed mailing labels. It uses one column, and has the address info in separate rows:
Name
Street Address
City, ST ZIP
Name
Street Address
City, ST ZIP
Name
Street Address
City, ST ZIP
What I need to do is transpose the data into columns, with separate columns for City, ST, and ZIP (for carrier route sorting). My initial thought was to use Pivot, but I couldn't seem to get that to work.
There are 1,800+ names in this mailing list, so manually fixing it is not an option. I also had an idea to export them as a CSV, and then use a series of find and replace operations to replace line breaks with commas, but that seems bush league. There has to be a proper data solution.
Ideas?
Thanks,
ty

This is my solution. It is based on the assumption that the structure that you've described is fixed and consistent.
It is in written T-SQL (SQL Server). You shouldn't have any problem converting it to my-sql.
I am against the vba solution. SQL is powerful enough.
If you have hard time implementing this, I have a few more ideas. (I'm just not sure what's available in my-sql and have to check it out). Any way - It should work.
--DROP TABLE Example_Table;
CREATE TABLE Example_Table
(
Val VARCHAR(1000),
Row_Num INT IDENTITY(1,1)
);
INSERT INTO Example_Table
SELECT 'John' AS Val UNION ALL
SELECT 'Elm St.' AS Val UNION ALL
SELECT 'Tel Aviv, 151515' AS Val UNION ALL
SELECT 'Doe' AS Val UNION ALL
SELECT 'Manhatten St.' AS Val UNION ALL
SELECT 'Jerusalem, 344343' AS Val UNION ALL
SELECT 'Fox' AS Val UNION ALL
SELECT 'Mulder St.' AS Val UNION ALL
SELECT 'San Francisco, 3243424' AS Val UNION ALL
SELECT 'Jean Lic' AS Val UNION ALL
SELECT 'Picard St.' AS Val UNION ALL
SELECT 'Enterprise City, 3904734' AS Val;
SELECT Name_Details.Val AS Name
, Street_Details.Val AS Street
, SUBSTRING(City_Details.Val, 1, CHARINDEX(',', City_Details.Val, 0) - 1) AS City
, SUBSTRING(City_Details.Val, CHARINDEX(',', City_Details.Val, 0) + 2, LEN(City_Details.Val) - CHARINDEX(',', City_Details.Val, 0)) AS Zip
, City_Details.Val AS City_And_Zip
FROM Example_Table AS Name_Details
INNER JOIN
(SELECT VAL, Row_Num FROM Example_Table AS E WHERE Row_Num % 3 = 2) AS Street_Details
ON (Street_Details.Row_Num = Name_Details.Row_Num + 1)
INNER JOIN
(SELECT VAL, Row_Num FROM Example_Table AS E WHERE Row_Num % 3 = 0) AS City_Details
ON (City_Details.Row_Num = Name_Details.Row_Num + 2)
WHERE Name_Details.Row_Num % 3 = 1 ;
DROP TABLE Example_Table;

Related

SQL: Joining 3 tables to generate report dashboard

I am trying to join 3 different tables that holds my test execution results as "PASS", "FAIL" and "SKIP". There are 2 common properties in these 3 tables on the basis of which I need to club my result i.e. "BUILD_NUMBER" and "COMPONENT".
Tried several approach but does not get the desired result.
Best result reached so far.
Sample query:
select test_execution.COMPONENT, test_execution.BUILD_NUMBER,
count(test_execution.TEST_STATUS) as PASS from (test_execution
INNER JOIN test_execution_fail ON
test_execution.BUILD_NUMBER = test_execution_fail.BUILD_NUMBER) group by
COMPONENT,BUILD_NUMBER;
My tables look like below:
CREATE TABLE test_execution_skip (
BUILD_NUMBER int,
TEST_NAME varchar(255),
TEST_CLASS varchar(255),
COMPONENT varchar(255),
TEST_STATUS varchar(255)
);
Other two tables are exactly same with test_execution and test_execution_fail as their names.
test_execution table holds 3 records(all pass values), test_execution_fail table holds 2 records (all fail values) and test_execution_skip table holds 1 record(skip value).
I want to populate data that will show me BUILD_NUMBER, COMPONENT, TOTAL, PASS, FAIL, SKIP as records where TOTAL, PASS, FAIL and SKIP will show the respectives counts.
Any help is appreciated here.
Not sure if this answers your question but you could try something like this
WITH cte AS (
SELECT * FROM test_execution
union
SELECT * FROM test_execution_fail
UNION
SELECT * FROM test_execution_skip
)
SELECT t.*, (SKIP + FAIL + PASS) AS TOTAL FROM (
select
COMPONENT,
BUILD_NUMBER,
SUM(IF(TEST_STATUS = 'skip', 1, 0 )) as SKIP,
SUM(IF(TEST_STATUS = 'fail', 1, 0 )) as FAIL,
SUM(IF(TEST_STATUS = 'pass', 1, 0 )) as PASS
FROM cte
group by COMPONENT,BUILD_NUMBER
)t
db fiddle

Merge two databases, without duplicates, with FKs references [duplicate]

I have two mdb files.
I can also convert it to MySQL database, if necessary.
How can I merge these two different dbs to a single one?
The idea is to get all info form both dbs and merge into one, without duplicating any client.
The problem is that both bds have the same clients, and different ones, but the PKs of the clients aren't the same on them.
Every line has a unique field, I guess it can help somehow.
Any idea of how can I do that?
Select a UNION all columns except the PKs will give you only distinct rows:
insert into new_table (<non-pk columns>)
select <non-pk columns> from tableA
union
select <non-pk columns> from tableB
Note: union removes duplicates.
I would run an UPDATE to populate one of the tables w/ all info available.
Assuming the first table has all names that the second table has (that there are no name values in table 2 that are not in table 1) you should be able to run the following update to make the first table complete:
update tclient1 t join (select name,
max(tel) as tel_filled,
max(address) as add_filled
from (select name, tel, address
from tclient1
union all
select name, tel, address
from tclient2) x
group by name) x on t.name = x.name
set t.tel = x.tel_filled and t.address = x.add_filled;
See fiddle: http://sqlfiddle.com/#!2/3e7dc/1/0
Disable foreign keys (see here)
Update FK in the 2nd DB so make them unique, for instance:
update Client
set id_client = id_client + 100000000;
update History
set id_client = id_client + 100000000,
id_history = id_history + 10000000;
Enable FKs to check integrity
Export 2nd DB as SQL-inserts and execute it in the 1st DB.
Use backups, please.
Here is one approach that assumes that name is the match between the two rows. It just counts the numbers that are filled in and chooses the appropriate source. This version uses union all with a comparison in the where using >= or <:
insert into client(id, name, tel, address)
select id, name, tel, address
from db1.client c1
where ((id is not null) + (tel is not null) + (address is not null)) >=
(select (id is not null) + (tel is not null) + (address is not null)
from db2.client c2
where c1.name = c2.name
)
)
union all
select id, name, tel, address
from db2.client c2
where ((id is not null) + (tel is not null) + (address is not null)) >
(select (id is not null) + (tel is not null) + (address is not null)
from db1.client c1
where c2.name = c1.name
)
);
Note: the above version assumes that name is in both tables (as in the example in your question) and there are no duplicates. It can be easily modified if this isn't the case.

How to merge two databases, with same data, but with different PKs, without duplicated fields?

I have two mdb files.
I can also convert it to MySQL database, if necessary.
How can I merge these two different dbs to a single one?
The idea is to get all info form both dbs and merge into one, without duplicating any client.
The problem is that both bds have the same clients, and different ones, but the PKs of the clients aren't the same on them.
Every line has a unique field, I guess it can help somehow.
Any idea of how can I do that?
Select a UNION all columns except the PKs will give you only distinct rows:
insert into new_table (<non-pk columns>)
select <non-pk columns> from tableA
union
select <non-pk columns> from tableB
Note: union removes duplicates.
I would run an UPDATE to populate one of the tables w/ all info available.
Assuming the first table has all names that the second table has (that there are no name values in table 2 that are not in table 1) you should be able to run the following update to make the first table complete:
update tclient1 t join (select name,
max(tel) as tel_filled,
max(address) as add_filled
from (select name, tel, address
from tclient1
union all
select name, tel, address
from tclient2) x
group by name) x on t.name = x.name
set t.tel = x.tel_filled and t.address = x.add_filled;
See fiddle: http://sqlfiddle.com/#!2/3e7dc/1/0
Disable foreign keys (see here)
Update FK in the 2nd DB so make them unique, for instance:
update Client
set id_client = id_client + 100000000;
update History
set id_client = id_client + 100000000,
id_history = id_history + 10000000;
Enable FKs to check integrity
Export 2nd DB as SQL-inserts and execute it in the 1st DB.
Use backups, please.
Here is one approach that assumes that name is the match between the two rows. It just counts the numbers that are filled in and chooses the appropriate source. This version uses union all with a comparison in the where using >= or <:
insert into client(id, name, tel, address)
select id, name, tel, address
from db1.client c1
where ((id is not null) + (tel is not null) + (address is not null)) >=
(select (id is not null) + (tel is not null) + (address is not null)
from db2.client c2
where c1.name = c2.name
)
)
union all
select id, name, tel, address
from db2.client c2
where ((id is not null) + (tel is not null) + (address is not null)) >
(select (id is not null) + (tel is not null) + (address is not null)
from db1.client c1
where c2.name = c1.name
)
);
Note: the above version assumes that name is in both tables (as in the example in your question) and there are no duplicates. It can be easily modified if this isn't the case.

SQL find next available string key

I need to find the next available ID on a table that has keys that are strings. I have followed an example here. My example below:
Dishes Table (first columns)
Table_id
DSH0000000003
DSH0000000004
DSH0000000005
DSH0000000007
SQL:
SELECT CONCAT('DSH',LPAD(MIN(SUBSTRING(t1.dish_id FROM 4) + 1), 10, '0')) AS nextID
FROM dishes t1
WHERE NOT EXISTS (SELECT t2.dish_id
FROM dishes t2
WHERE SUBSTRING(t2.dish_id FROM 4) = SUBSTRING(t1.dish_id FROM 4) + 1)
Output:
DSH0000000006
If I delete #5 then it returns #5 but it does not return "DSH0000000001".
You may use variables to build consecutive ids, then compare where's first non-matched id:
SELECT
CONCAT('DSH', LPAD(seq, 10, '0')) AS k
FROM
(SELECT
#seq:=#seq+1 AS seq,
num
FROM
(SELECT
CAST(SUBSTR(table_id, 4) AS UNSIGNED) AS num
FROM
t
UNION ALL
SELECT
MAX(CAST(SUBSTR(table_id, 4) AS UNSIGNED))+2 AS num
FROM
t
ORDER BY
num) AS ids
CROSS JOIN
(SELECT #seq:=0) AS init
) AS pairs
WHERE
seq!=num
LIMIT 1
Fiddle is available here.
You should add a test of your start value. With your current approach you can only get values greater than the minimum value that exists in your table.
You could use IF() to distinguish the two possibilities.

What is the cleanest way of the following (MySQL)

I have a huge cities table containing around 3,000,000 rows. I needed to create a new column which contains the following line:
'City name, City name with accent, Country name'
Basic Schema is as follows:
city_id int
name varchar
status varchar
date_created int(11)
country_id int
accent_name varchar
city_country text
And there is the countries table which contains the contry_id and its name.
Now I figured out 2 ways to fill the city_country column.
Attempt 1:
delimiter //
CREATE FUNCTION getConcat(x INT(11))
RETURNS TEXT
READS SQL DATA
BEGIN
DECLARE var1 TEXT;
SELECT concat(CT.name, ', ', CT.accent_name, ', ', CR.name) AS Combined INTO var1 FROM `wp_City` AS CT LEFT JOIN `wp_Country` AS CR ON CR.country_id = CT.country_id WHERE CT.city_id = x;
RETURN var1;
END//
UPDATE `wp_City` SET `city_country`=(SELECT getConcat(city_id)) WHERE 1;
Attempt 2:
I created a new table containing just one column:
INSERT INTO `_myCity` (name, status, date_created, country_id, accent_name, lat, `long`, region, city_country)
SELECT c.name, c.status, c.date_created, c.country_id, c.accent_name, c.lat, c.long, c.region, _c.name
FROM `wp_City` as c inner join `wp_Country` _c on c.country_id = _c.country_id
Now the second way is much faster, but which is cleaner? The above will be executed only once, so the question is simply out of curiosity. If there are better ways of achieving this please do share!!
Thank you in advance.
If I were to do something like this I would rather go with a view that adds the column when needed (thus avoiding the additional overhead imposed by storing redundant data in the table on disk)