Handle dynamic missed columns in MySQL - mysql

I have a small doubt in MySQL. While loading data from one table to another table I faced one issue
first table: emp
id | name | sal | deptno | loc | referby
1 | abc | 100 | 10 | hyd | xyz
2 | mnc | 200 | 20 |chen | pqr
second table:emprefers
id | name | sal | deptno | loc | referby
Now I want to load the emp table data into the emprefers table. I wrote a query like
insert into emprefers select * from emp after
I ran the query, the data was loaded into the emprefers table like below:
id | name | sal |deptno | loc |referby
1 | abc | 100 | 10 | hyd | xyz
2 | mnc | 200 | 20 | chen | pqr
Now I ran the same query a second time. It has failed. The reason is the name column is deleted from the emp table.
I edited the query like:
insert into emprefers select id,'null'as name,sal,deptno,loc,referby from emp
After I ran the edited query again, now records are loading into the emprefers table and the data looks like:
id | name | sal |deptno | loc |referby
1 | null | 100 |10 | hyd | xyz
2 | null | 200 |20 |chen | pqr
Every time before loading the emprefers table I truncate the emprefers table data. And the emprefers table structure never changed.
Again, a third time I ran the same query again. The query has failed, the reason was that the sal and deptno columns were missing in the emp table.
I don't want to edit the query again, reason is we don't know which columns are/get deleted from the emp table.
This time we want solve the issue.
We want to load the data into the second table if the columns are available in the emp table, then load the data - otherwise we need to pass null or empty values for those columns.
Please tell me how to write a query to check if a column exist or not, and if it exists to retrieve the same column, otherwise assign null values for that column.

Rather than changing the existing query and truncating the table, it might be a better idea to make delete the whole table, make a copy of the original emp table and then insert the data into it. That way they'll always be the same.
DROP TABLE emprefers IF EXISTS
CREATE TABLE emprefers LIKE emp;
INSERT INTO emprefers SELECT * FROM emp

This statement will create the table over the fly.
CREATE TABLE databasename.emprefers SELECT * FROM databasename.emp;

Related

Mysql query to get distinct row with column having null and duplicate values

So I have a weird situation in which I have a table like this :
mysql> select * from test;
+-------+------+
| name | sal |
+-------+------+
| agent | 1000 |
| agent | 2000 |
| NULL | 3000 |
| NULL | 4000 |
| smith | 5000 |
| smith | 6000 |
| neo | 7000 |
+-------+------+
I want to return a data set which looks like this :
+-------+------+
| name | sal |
+-------+------+
| agent | 1000 |
| NULL | 3000 |
| NULL | 4000 |
| smith | 5000 |
| neo | 7000 |
+-------+------+
Meaning I want to fetch unique rows wherever name is duplicated, but fetch all rows as it is when name is null or is not duplicated.
I have written this query below in order to achieve that and it works fine. But I want to optimize it.
select *
from test
where sal in (
select sal from (
select min(sal) as sal
from test
group by name
union
select sal
from test where name is null
) t
order by sal);
Queries for creating this sample data -
create table test (name text, sal int);
insert into test values ('agent',1000);
insert into test values ('agent',2000);
insert into test values (null,3000);
insert into test values (null,4000);
insert into test values ('smith',5000);
insert into test values ('smith',6000);
insert into test values ('neo',7000);
Can anyone help me with that? I know that we shouldn't use IN to fetch data because that will increase the query time a lot in production.
Any help is appreciated!
You can try to use two queries with UNION ALL one is for name which value is null, another one writes MIN aggregate function by name with name isn't NULL.
Query #1
SELECT *
FROM (
SELECT name,sal
FROM test
WHERE name IS NULL
UNION ALL
SELECT name,min(sal)
FROM test
WHERE name IS NOT NULL
group by name
)t1
ORDER BY sal;
name
sal
agent
1000
3000
4000
smith
5000
neo
7000
View on DB Fiddle
Note
You can try to create an index on name column which might help you improve the query performance

Replace current table data with result from querying the same table

I have a table that does not have any index or primary key in my MySQL database. I cannot change the schema of the table (it is not "my" table). As the table stores data that arrives in intervals, there can be (are) duplicates.
For example:
+--------------+--------------+--------+----------+----------+---------+
| first_seen | last_seen | type | name | hitcnt | data |
+--------------+--------------+--------+----------+----------+---------+
| 15:12:02 | 16:02:32 | 5 | foo | 3 | difank |
+--------------+--------------+--------+----------+----------+---------+
| 19:52:23 | 22:06:20 | 5 | foo | 4 | difank |
+--------------+--------------+--------+----------+----------+---------+
Now I would like to "reduce" this to:
+--------------+--------------+--------+----------+----------+---------+
| first_seen | last_seen | type | name | hitcnt | data |
+--------------+--------------+--------+----------+----------+---------+
| 15:12:02 | 22:06:20 | 5 | foo | 7 | difank |
+--------------+--------------+--------+----------+----------+---------+
And I would like to do this "in situ" (i.e. in place) if possible.
Using GROUP BY, MIN(), MAX(), etc. I can write a query that returns exactly what I want to end up with:
SELECT
MIN(first_seen),
MAX(last_seen),
type,
name,
SUM(hitcnt) as hit,
data
FROM <table>
GROUP BY type, name, data
ORDER BY hit desc, type;
The question is: how can I replace the existing data (efficiently) with the result of that query?
Do I have to use a temporary table (i.e. move the data to a temporary table, truncate the existing table and SELECT INTO from the temporary table)?
Can I do this in a transaction (to prevent data loss if something goes wrong)?
Are there other (better?) options than a temporary table?
TRUNCATE TABLE table_name;
INSERT INTO table_name (column1.....)
SELECT
MIN(first_seen),
MAX(last_seen),
type,
name,
SUM(hitcnt) as hit,
data
FROM <table>
GROUP BY type, name, data
ORDER BY hit desc, type;
Make sure number of columns of insert and select staement matches.
I ended up using the following approach:
CREATE TABLE tmp_table IF NOT EXISTS AS (SELECT ...);
then move the "new" table into place using ALTER TABLE ... RENAME ...;
followed by a DROP TABLE ...; for the old/original table.
That seems to work.

Access 2007 Query to return latest date note from subquery

I have 2 tables joined by ProjectID in Access 2007. Table structure of primary table (A) is like
ProjectID | CustID
1 | 5
2 | 8
I have a secondary table (B) of notes on the ProjectID, structured like
ProjectNotesID | ProjectID | Note | CreateDate
---------------------------------------------------
1 | 1 | Note11 | 1/2/2015
2 | 1 | Note12 | 2/2/2015
3 | 2 | Note21 | 4/8/2015
4 | 2 | Note22 | 3/5/2015
I want to return all of, or part of, Table A, with the latest note of Table B, something like
ProjectID | CustID | Note | CreateDate
------------------------------------------
1 | 5 | Note12 | 2/2/2015
2 | 8 | Note21 | 4/8/2015
I can do (and have done) this with PHP & MySQL, but can't get it to work in Access 2007. I can return the ProjectID and latest Note date by the following query in Access 2007
SELECT ProjectID, Max(CreateDate) AS MaxOfCreateDate
FROM Table B
GROUP BY ProjectID;
I have tried Unique Values, etc., but can't get the results I am looking for.
Thanks!
Pete
I found an answer. First, I changed the query where I got the latest date, and instead got the max ProjectNotesID. The query is ::
SELECT ProjectID, Max(ProjectNotesID) AS MaxOfProjectNotesID
FROM Table B
GROUP BY ProjectID;
I then created a second query combining the above query and Table B, joining Query.MaxOfProjectNotesID <-> TableB.ProjectNotesID, and Query.ProjectID <-> TableB.ProjectID. The second query pulls all values from TableB.

SQL query to remove multiple duplicate entries from table

I have table containing following entries
Id | Accno | Name | Hash
----+----------+-----------+---------
1 | 11 | ABC | 01110
2 | 11 | ABC |
3 | 22 | PQT |
4 | 33 | XYZ | 03330
5 | 44 | LMN | 04440
6 | 33 | XYZ |
I need SQL query to remove duplicate entry from table and keep atleast single entry in table whose hash value is present. and for those entries which are not duplicate should also remain in table.
I think you guys overcomplicate things a lot. This should work just dandy:
DELETE FROM
YourTable
WHERE Hash IS NULL
AND Accno IN
(
SELECT Accno
FROM YourTable
GROUP BY Accno
HAVING COUNT(Name) > 1
)
;
Probably the easiest way to do it is to create a new table and copy non duplicate entries.
create table table_name2 as select distinct * from table_name1;
drop table table_name1;
rename table_name2 to table_name1;
Something like this.
Create table temp2 as SELECT *
FROM temp where id in (select id from temp group by accno having count(accno)>=1 and hash<>'');
drop table old_table;
rename table temp2 to old_table;
Check SQL Fiddle

Combine count rows in MySQL

I've got a table in MySQL that looks roughly like:
value | count
-------------
Fred | 7
FRED | 1
Roger | 3
roger | 1
That is, it was created with string ops outside of MySQL, so the values are case- and trailing-whitespace-sensitive.
I want it to look like:
value | count
-------------
Fred | 8
Roger | 4
That is, managed by MySQL, with value a primary key. It's not important which one (of "Fred" or "FRED") is kept.
I know how to do this in code. I also know how to generate a list of problem values (with a self-join). But I'd like to come up with a SQL update/delete to migrate my table, and I can't think of anything.
If I knew that no pair of records had variants of one value, with the same count (like ("Fred",4) and ("FRED",4)), then I think I can do it with a self-join to copy the counts, and then an update to remove the zeros. But I have no such guarantee.
Is there something simple I'm missing, or is this one of those cases where you just write a short function outside of the database?
Thanks!
As an example of how to obtain the results you are looking for with a SQL query alone:
SELECT UPPER(value) AS name, SUM(count) AS qty FROM table GROUP BY name;
If you make a new table to hold the correct values, you INSERT the above query to populate the new table as so:
INSERT INTO newtable (SELECT UPPER(value) AS name, SUM(count) AS qty FROM table GROUP BY name);
Strangely, MySQL seems to do this for you. I just tested this in MySQL 5.1.47:
create table c (value varchar(10), count int);
insert into c values ('Fred',7), ('FRED',1), ('Roger',3), ('roger',1);
select * from c;
+-------+-------+
| value | count |
+-------+-------+
| Fred | 7 |
| FRED | 1 |
| Roger | 3 |
| roger | 1 |
+-------+-------+
select value, sum(count) from c group by value;
+-------+------------+
| value | sum(count) |
+-------+------------+
| Fred | 8 |
| Roger | 4 |
+-------+------------+
I was surprised to see MySQL transform the strings like that, and I'm not sure I can explain why it did that. I was expecting to have to get four distinct rows, and to have to use some string functions to map the values to a canonical form.