Pre populate Sql data using recursion on each combination - mysql

I am trying to fill db pre populated data from sql script where I have two type of constants or enums.
Platform: DG, NK
Department : KK, TG, LO, NP, UI, BG, ED, CC.
Task: To generate a sequential number using procedural loop and for each combination using above value we need to generate key and put in data base with count or sequence value.
Database columns:
id(auto generated), count, category_key, status
Now single row would be one combination which is formed using this pattern,
Department_Platform_SequenceNumber :: example => KK_DG_1,....KK_DG_10000, KK_NK_1,....KK_NK_10000
This is for 10k entries for 10k sequence of each combinations. It follows for other as well.
Approach:
WITH RECURSIVE
number AS ( SELECT 1 number
UNION ALL
SELECT number + 1 FROM cte WHERE number < 10000 ),
platform AS ( SELECT 'DG' platform
UNION ALL
SELECT 'NK' ),
department AS ( SELECT 'KK' department
UNION ALL
SELECT 'TG'
UNION ALL
SELECT 'LO'
UNION ALL
SELECT 'NP'
UNION ALL
SELECT 'UI'
UNION ALL
SELECT 'BG'
UNION ALL
SELECT 'ED'
UNION ALL
SELECT 'CC' )
INSERT INTO counter_key
SELECT null, number, CONCAT_WS('_', department, platform, number), 1
FROM department
CROSS JOIN platform
CROSS JOIN number;
Problem: Getting syntactical error::
Error Code: 1064. You have an error in your SQL syntax; check the
manual that corresponds to your MySQL server version for the right
syntax to use near 'INSERT INTO counter_key SELECT null, number,
CONCAT_WS('_', department, platfor' at line 23
Please help me resolve this since I have been struggling to resolve this.

There are 2 problems in query
cte does not exist in first Recursive Block.
Place the Insert INTO statement before recursive block
So your final query should be like below
insert into counter_key
WITH RECURSIVE
cte AS ( SELECT 1 number
UNION ALL
SELECT number + 1 FROM cte WHERE number < 2 ),
platform AS ( SELECT 'DG' platform
UNION ALL
SELECT 'NK' ),
department AS ( SELECT 'KK' department
UNION ALL
SELECT 'TG'
UNION ALL
SELECT 'LO'
UNION ALL
SELECT 'NP'
UNION ALL
SELECT 'UI'
UNION ALL
SELECT 'BG'
UNION ALL
SELECT 'ED'
UNION ALL
SELECT 'CC' )
SELECT null, number, CONCAT_WS('_', platform, department), 1
FROM department
CROSS JOIN platform
CROSS JOIN cte
order by 3,2;
DEMO

Related

Get records as per the given ids' mysql

This is the query i am executing
SELECT email,firstname,lastname FROM `sco_customer`
WHERE id_customer IN (7693,7693,7693,7693,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,7693,3,3,3,3,3,7693,7693,3,3,3,7693,3,3,3)
This gives me only two records as their are same number of id_customer is filtered i.e 7693,3
email firstname lastname
abc#any.com Test Mage
abc2#any.com User Mage
It should give the same number of records as much is the id_customer
Any thoughts how this can be achieved ?
Try below. Instead of WHERE clause you can generate a dummy table and join it with your main table.(WITH works for version 8 or above)
WITH SAMPLE AS
(
SELECT 7693 AS ID FROM DUAL
UNION ALL
SELECT 3 AS ID FROM DUAL
)
SELECT email,firstname,lastname FROM `sco_customer`
INNER JOIN SAMPLE ON SAMPLE.ID=ID_CUSTOMER
Below mysql version 8:
SELECT email,firstname,lastname FROM `sco_customer`
INNER JOIN (
SELECT 7693 AS ID FROM DUAL
UNION ALL
SELECT 3 AS ID FROM DUAL
)SAMPLE ON SAMPLE.ID=ID_CUSTOMER
The following statement should solve you problem:
SELECT email,firstname,lastname FROM `sco_customer`
join (select 7693 as id_customer union all
select 7693 union all
select 7693 union all
select 3 union all
select 3 union all
select 3
) tmp on sco_customer.id_customer = tmp.id_customer

How to include empty rows in Access query results

I have an Access 2010 database with client information. I need to create a table of the number of clients in each age. The agency I am reporting to wants a report with the number of clients of every age from 0 - 100 years listed. The SQL query below will create the required report, but does not include ages with zero clients.
SELECT AgeNum & " years" AS [Age], Count(*) AS [Count]
FROM (SELECT Int(DateDiff("d", Clients.dob, now())/365.25) AS AgeNum
FROM Clients) AS [%$###_Alias]
GROUP BY [%$###_Alias].AgeNum;
How can I have the query return the empty rows with 0 in the Count column?
I looked around and found this:
How can I create a row for values that don't exist and fill the count with 0 values?
They create a table of values to lookup the empty groups. It is very similar to what I need except it uses a Coalesce function which is not supported in Access 2010.
The system only knows there is an age if a particular record exists. If you want to have a list of age between 1..100, you need to tell or provide the system that you are looking for 0..100 ages. By providing a list of ages you are looking for, system will automatically return 0/null if the requested age is not found withing your searched records.
As others mentioned, you can have a table with 1..100 as rows and compare them in your SQL or you could generate list of numbers with SQL.
Some DBMS provide a default table called dual which has one column and one row, you can use that table for any queries that does not have a from table.
In your access application, create a table called "dual" and insert one row.
Now execute this query:
SELECT TMain.counter
FROM (SELECT (T2.mAge*t3.mFactor10)+t1.mAge AS counter
FROM (select 1 as mAge from dual
union all select 2 from dual
union all select 3 from dual
union all select 4 from dual
union all select 5 from dual
union all select 6 from dual
union all select 7 from dual
union all select 8 from dual
union all select 9 from dual
union all select 10 from dual) AS T1,
(select 0 as mAge from dual
union all select 1 from dual
union all select 2 from dual
union all select 3 from dual
union all select 4 from dual
union all select 5 from dual
union all select 6 from dual
union all select 7 from dual
union all select 8 from dual
union all select 9 from dual
union all select 10 from dual) AS T2,
(select 10 as mFactor10 from dual) AS T3 ) AS TMain
WHERE (((TMain.counter) Between 1 And 100));
this will produce 100 rows from 1..100.
you can then use this result as outer table for your SQL and find/count anyone whose age is on this list.
the logic would be:
select all age
from the reqeusted age list
find and count/return all matched records or return 0 if no records found.
In SQL, it would be something like this,
SELECT TMain.counter as Age,
(SELECT Count(*) AS [Count]
FROM (SELECT Int(DateDiff("d", Clients.dob, now())/365.25) AS AgeNum
FROM Clients) AS [%$###_Alias]
WHERE (TMain.counter = [%$###_Alias].ageNum)
GROUP BY [%$###_Alias].AgeNum) as number_of_clients
FROM (SELECT (T2.mAge*t3.mFactor10)+t1.mAge AS counter
FROM (select 1 as mAge from dual
union all select 2 from dual
union all select 3 from dual
union all select 4 from dual
union all select 5 from dual
union all select 6 from dual
union all select 7 from dual
union all select 8 from dual
union all select 9 from dual
union all select 10 from dual) AS T1,
(select 0 as mAge from dual
union all select 1 from dual
union all select 2 from dual
union all select 3 from dual
union all select 4 from dual
union all select 5 from dual
union all select 6 from dual
union all select 7 from dual
union all select 8 from dual
union all select 9 from dual
union all select 10 from dual) AS T2,
(select 10 as mFactor10 from dual) AS T3 ) AS TMain
WHERE (((TMain.counter) Between 1 And 100));
this will produce: age from 1..100 as well as number of clients for each age and null for null/empty no results .
of course, you can dynamically extend or shorten the age list.
You can use instead of COALESCE Nz function:
Nz([Age],0)
And yes, your link should work for you.
Create a 'sequence' table of all possible integers (FYI in UK medical data dictionaries we use 220 as the maximum age in years), then 'anti-join' to this table. You could use a view for your original results.
The following SQL DDL requires ANSI-92 Query Mode (probably better for the SQL Server coder than the default Query Mode) but can also be created maually using the Access GUI tools:
CREATE TABLE Seq ( seq INT NOT NULL UNIQUE );
INSERT INTO Seq VALUES ( 1 );
INSERT INTO Seq VALUES ( 2 );
INSERT INTO Seq VALUES ( 3 );
...
(you can use Excel to create this script!)
...
INSERT INTO Seq VALUES ( 100 );
CREATE VIEW ClientAgeTallies ( AgeInYears, Tally )
AS
SELECT dt.AgeInYears, COUNT(*) AS Tally
FROM ( SELECT INT(DATEDIFF( 'd', c.dob, NOW() ) / 365.25) AS AgeInYears
FROM Clients AS c ) AS dt
GROUP
BY dt.AgeInYears;
SELECT AgeInYears, Tally
FROM ClientAgeTallies
UNION
SELECT seq AS AgeInYears, 0 AS Tally
FROM Seq
WHERE seq NOT IN ( SELECT AgeInYears FROM ClientAgeTallies );

MySQL Query Optimization for running total query - How can I reduce query exectuion time?

Problem
I have a query that I pasted below. The problem I face is how can I trim the latency to under the current time of about 10 seconds.
set# csum = 0;
SELECT Date_format(assigneddate, '%b %d %Y') AS assigneddate, (#csum: = #csum + numactionitems) AS totalactionitems
FROM(
SELECT assigneddate,
Sum(numactionitems) AS numactionitems FROM(
SELECT assigneddate,
Count( * ) AS numactionitems FROM(
SELECT *
FROM(
SELECT actionitemtitle,
actionitemstatement,
altownerid,
approvalstatement,
assigneddate,
assignorid,
closeddate,
closurecriteria,
closurestatement,
criticality,
duedate,
ecd,
notes,
ownerid,
Concat(lastname, ', ', firstname) AS owner,
cnames2.categoryvalue AS `team`,
cnames2.categorynameid AS `teamid`,
cnames3.categoryvalue AS `department`,
cnames3.categorynameid AS `departmentid`,
cnames4.categoryvalue AS `source`,
cnames4.categorynameid AS `sourceid`,
cnames5.categoryvalue AS `project_phase`,
cnames5.categorynameid AS `project_phaseid`,
ac1.actionitemid FROM actionitemcategories AS ac1 INNER JOIN actionitems AS a INNER JOIN users AS u INNER JOIN(
SELECT actionitemid AS a2id,
categorynameid AS c2 FROM actionitemcategories WHERE categoryid = 195) AS ac2 INNER JOIN categorynames AS cnames2 ON cnames2.categorynameid = ac2.c2 AND ac1.categoryid = 195 AND a.actionitemid = ac2.a2id AND ac1.actionitemid = a.actionitemid AND a.ownerid = u.userid INNER JOIN(
SELECT actionitemid AS a3id,
categorynameid AS c3 FROM actionitemcategories WHERE categoryid = 200) AS ac3 INNER JOIN categorynames AS cnames3 ON cnames3.categorynameid = ac3.c3 AND ac2.a2id = ac3.a3id INNER JOIN(
SELECT actionitemid AS a4id,
categorynameid AS c4 FROM actionitemcategories WHERE categoryid = 202) AS ac4 INNER JOIN categorynames AS cnames4 ON cnames4.categorynameid = ac4.c4 AND ac3.a3id = ac4.a4id INNER JOIN(
SELECT actionitemid AS a5id,
categorynameid AS c5 FROM actionitemcategories WHERE categoryid = 203) AS ac5 INNER JOIN categorynames AS cnames5 ON cnames5.categorynameid = ac5.c5 AND ac4.a4id = ac5.a5id) s WHERE 1 = 1) f GROUP BY assigneddate UNION ALL(
SELECT a.date AS assigneddate,
0 AS numactionitems FROM(
SELECT '2015-03-05' + INTERVAL(a.a + (10 * b.a) + (100 * c.a)) day AS date FROM(
SELECT 0 AS a UNION ALL SELECT 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) AS a CROSS JOIN(
SELECT 0 AS a UNION ALL SELECT 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) AS b CROSS JOIN(
SELECT 0 AS a UNION ALL SELECT 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) AS c) a) ORDER BY assigneddate ASC) t GROUP BY assigneddate LIMIT 282) t
WHERE assigneddate != '0000-00-00'
Purpose of Query
The purpose of this query is to get all records that contain date values and to collect the running count of all records that fall on a certain date. Date values are computed within the sqlfiddle below. It's final purpose is to be displayed in a graph that takes the running total as a line graph. It will be counting upwards so it is a growing graph.
The graph I am displaying it in is called a build-up graph of all my records (action items with date values).
Description of Issue
My problem is that I am getting the results of the query in at least 10 seconds.
Question
How can I accelerate and reduce the latency of the query so that I will not stall the loading of my graph?
Complete Schema and portion of my above query that Runs Successfully
(I am having difficulty getting the main query to run at all on sqlfiddle, though I can run it from my own machine).
http://sqlfiddle.com/#!9/865ee/11
Any help or suggestions would be tremendously appreciated!
EDIT
ADDED Sample Screenshot of my Categories Interface
Category (First Table) has a field called categoryname which assumes one of 4 values can be expanded or deleted which is - Team, Department, Source, Project_Phase.
CategoryName (Second Table) has a field called categoryvalue which is the actual allowed value for each category (First Table)
Example - Team 1, Team 2, Team 3 are categoryvalues within categoryname and corresponding the category of Team.
Category
Start by making that table of dates a permanent table, not a subquery.
This construct performs very poorly, and can usually be turned into JOINs without subqueries:
JOIN ( SELECT ... )
JOIN ( SELECT ... )
This is because there is no index on the subqueries, so full scans are needed.
Provide EXPLAIN for the entire query.
Addenda
A PRIMARY KEY is a key; don't add another key with the same column(s).
EAV schema leads to complexity and sluggishness that you are encountering.
Don't use TINYTEXT; it slows down tmp tables in complex queries; use VARCHAR(255). Don't use VARCHAR(255), use VARCHAR with a realistic limit.
Why do you need both categories and categorynames?

mysql find numbers in query that are NOT in table

Is there a simple way to compare a list of numbers in my query to a column in a table to return the ones that are NOT in the db?
I have a comma separated list of numbers (1,57, 888, 99, 76, 490, etc etc) that I need to compare to the number column in a table in my DB. SOME of those numbers are in the table, some are not. I need the query to return those that are in my comma separated list, but are NOT in the DB...
I would put the list of numbers to be checked in a table of their own, then use WHERE NOT EXISTS to check whether they exist in the table to be queried. See this SQLFiddle demo for an example of how this might be accomplished:
If you're comfortable with this syntax, you can even avoid putting into a temp table:
SELECT * FROM (
SELECT 1 AS mycolumn
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6
UNION
SELECT 7
) a
WHERE NOT EXISTS ( SELECT 1 FROM mytable b
WHERE b.mycolumn = a.mycolumn )
UPDATE per comments from OP
If you can insert your very long list of numbers into a table, then query as follows to get the numbers that are not found in the other table:
SELECT mynumber
FROM mytableof37000numbers a
WHERE NOT EXISTS ( SELECT 1 FROM myothertable b
WHERE b.othernumber = a.mynumber)
Alternately
SELECT mynumber
FROM mytableof37000numbers a
WHERE a.mynumber NOT IN ( SELECT b.othernumber FROM myothertable b )
Hope this helps.
May be this is what you are looking for.
Convert your CSV to rows using SUBSTRING_INDEX. Use NOT IN operator to find the values which is not present in DB
Then Convert the result back to CSV using Group_Concat.
select group_concat(value) from(
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.a, ',', n.n), ',', -1) value
FROM csv t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 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) a
,(SELECT 0 AS N UNION ALL SELECT 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) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.a) - LENGTH(REPLACE(t.a, ',', '')))) ou
where value not in (select a from db)
SQLFIDDLE DEMO
CSV TO ROWS referred from this ANSWER
You could use the 'IN' clause of MySQL. Maybe check this out IN clause tutorial

Combining tables while changing id - SQL

I'm trying to create a search function in different tables using UNION and what happened is that the id's are duplicating making the search go wrong. How can I merge different tables into one while no id's are in common?
Here is the example
table1
id name desc
1 henry post
2 albert doth
3 jun cloth
table2
id name desc
1 kin revenge
2 pot eve
The result SHOULD be like this
id name desc
1 henry post
2 albert doth
3 jun cloth
4 kin revenge
5 pot eve
Please help me. Thanks.
In most databases, you would add a new id using the ANSI standard row_number() function:
select row_number() over (order by which, id) as newid, name, description
from (select 1 as which, t1.* from table1 t1 union all
select 2 as which, t2.* from table2 t2
) t;
Note that desc is a really bad name for a column, because it is a SQL keyword and usually a reserved word.
EDIT:
MySQL doesn't support this ANSI standard functionality. Instead, use variables:
select (#rn := #rn + 1) as newid, name, description
from (select 1 as which, t1.* from table1 t1 union all
select 2 as which, t2.* from table2 t2
) t cross join
(select #rn := 0) vars
order by which, id;
I've include the order by so the rows remain in the same order that you seem to want them in -- rows from the first table followed by rows from the second table. If you don't care about the order, just drop the order by.
For SQLite, the calculation is much more painful:
with cte as (
select 1 as which, t1.* from table1 t1 union all
select 2 as which, t2.* from table2 t2
)
select (select count(*)
from cte cte2
where cte2.which < cte.which or (ct2.which = cte.which and cte2.id <= cte.id
) as id,
name, description
from cte;
In MySql, you can simulate the row_number() function of Sql Server and Oracle using a mutating variable hack:
set #rownum := 0;
SELECT #rownum:=#rownum+1 AS` row_number`, `name`, `desc`
FROM
(
SELECT `name`, `desc` FROM table1
UNION
SELECT `name`, `desc` FROM table2
) AS x;
SqlFiddle
It looks like you have to Generate Id's so you can make you Union query as Sub select and generate Id's in Outer Query
MySQL does not have any system function like SQL Server’s row_number () to generate the row number for each row. However, it can be generated using the variable in the SELECT statement
SET #row_number:=0;
SELECT #row_number:=#row_number+1 As Id,
NAME,
desc
FROM (SELECT NAME,desc
FROM table1
UNION ALL
SELECT NAME,desc
FROM table2
UNION ALL
........
........) A
Order by NAME -- Change the column in Order by in which order you want to create New ID's