FInd missing row based on Column data -MySQL - mysql

I am currently working on a.Net web form solution which generates a brief service report for admins to monitor the services done by technicians.As of now , i am having some trouble in coming up with an efficient SQL (for MySQl) which return data rows along with the missing rows based on the SertvicePrtNum , which is in order.
For Example :-
This is my raw data in the table :-
Id ServiceRptNum Customer_ID Date of Service
---- ------------- ----------- ---------------
1 1001 3 09/10/1997
2 1003 8 10/06/2005
3 1005 1 21/02/2003
4 1007 7 1/06/2011
5 1010 4 4/11/2012
6 1002 2 16/01/2003
Here the ServiceRptNum , 1004 is missing in the table. So i want the db to return the result as : -
Id ServiceRptNum Customer_ID Date of Service
---- ------------- ----------- ---------------
1 1001 3 09/10/1997
2 1002 2 16/01/2003
3 1003 8 10/06/2005
- 1004 - -
4 1005 1 21/02/2003
- 1006 - -
5 1007 7 1/06/2011
- 1008 - -
- 1009 - -
6 1010 4 4/11/2012
Here , the sql additionally generated 1004,1006,1008,1009 since it cannot find those records.
Please note that the Id is automatically generated (auto_increment)while insert of the data.But the Service ReportNum is not , this is to enable the admin to add the service report later on with the manually generated report Num (report num in the hardcopy of the company Servicebook).

You basically need to invent a constant, sequential stream of numbers and then left join your real data to them. For this method to work, you need a table with enough rows in it to generate a counter big enough:
select ID, 1000+n as servicerptnum, customer_id, `Date of Service` from
(
SELECT #curRow := #curRow + 1 AS n
FROM somebigtable
JOIN (SELECT #curRow := 0) r
WHERE #curRow<100
) numbergen
LEFT JOIN
tablewithmissingservicerptnum
ON
servicerptnum = 1000+n
You need to alter some things in the code above because you never told us the name of your table with missing rptnums. You also need to utilise another table in your database with more rows than this table because the way this method works is to count the rows in the bigger table, giving each a number. If you don't have any table bigger than this one, we can probably get enough rows by cross joining a smaller table to itself or by using this table. Replace somebigtable with thistable CROSS JOIN thistable where this table is the name of the table with missing servicerptnums
If you want just the rows that are missing, add a WHERE servicerptnum is null to the end of the sql
Edit, I see you've changed your numbering from:
1001
1002
...
1009
10010
To:
1009
1010
The join condition used to be servicerptnum = concat('100', cast(n as varchar)), it is now servicerptnum = 1000+n..

Look here for ideas on how to generate a group of continuous integers, then select from that left outer join your table. You should get a row for every number but all the values will be null for the missing numbers.

Related

msql count of items in each category into 2 columns by status with join

I’m a mysql newbie, recently installed mariadb to work on a project.
I have one table of many ITEMS, which are in various categories (catnum), and another table, STATUS, showing items (by id#) and their current status, either A or B.
I need to write a query that lists all of the categories (by catnum) and the total of all A’s and B’s in each category, something like this:
Desired result:
catnum statA statB
1001 22 15
1002 0 12
1003 14 8
1004 3 37
1005 24 0
1006 0 1
1007 47 5
etc
The ITEMS table looks like this:
itemid catnum
1 1205
2 1008
3 1010
4 1150
5 1782
6 1553
7 1004
etc
The STATUS table looks like this:
itemid stat
60 A
302 A
95 B
122 B
8 B
6 A
46 B
etc
The itemid in ITEMS is auto_increment, in case that matters.
I know (or think I know) that I need to use the following in some combination:
count(status.stat) or count(status.stat = A)
where items.itemid = status.itemid
where stat = A (then B)
group by catnum.
In some combinations I got error saying “Unknown column 'status.itemid' in 'having clause'” or other clause, despite that it exists. Why is that?
The closest I have gotten is to show each category and both status columns properly labeled but the number of B status items was incorrect, just a repeat of number of A status items.
SELECT
items.catnum,
count(status.stat=1) AS statA,
count(status.stat=2) AS statB
FROM
status
INNER JOIN
items
WHERE
items.itemid = status.itemid
GROUP BY
catnum;
(ALSO tried with ON instead of WHERE, same result, statB totals were wrong.)
I have explored self joins, inner joins, left/right joins, unions, subquery, and other techniques but I can’t seem to get to what I want. It seems like this must be a really common general query, but I can’t seem to find the right search terms to find it online. Any guidance would be appreciated.
Your query as it currently stands will simply return a COUNT of all the items in STATUS which have a given catnum. This is why the values for statA and statB are the same. What you need to do is SUM the occurrences of each status value. I've made a small SQLFiddle demo that shows this query in action:
SELECT
items.catnum,
SUM(status.stat='A') AS statA,
SUM(status.stat='B') AS statB
FROM items
JOIN status
ON items.itemid = status.itemid
GROUP BY items.catnum
Output (for the demo data):
catnum statA statB
1004 1 1
1008 2 1
1010 0 2
Note that in MySQL a boolean expression (e.g. status.stat='A') evaluates to 1 if true, 0 if false, so it can be summed directly.

how to patabless result of mysql stored procedure inside temporary

I have one stored procedure with one in parameter that returns multiple rows with 3 different columns. I want this result to be inserted inside another table with these 3 column filed and other tables individual fields.
However, when I create the temporary table it shows a blank resultset.
Can anybody help me to sort out this?
CREATE DEFINER=`root`#`localhost` PROCEDURE `getContactRolePermission`(
in contactroleid double
-- inout PermissionTableID double
)
BEGIN
select -- entitydetails.id,
contact.id as userid,
-- contacttyperolemap.contacttypeId ,
contacttyperolemap.roleid ,rolepermission.permissionid
from contacttyperolemap
join rolepermission on contacttyperolemap.roleid=rolepermission.roleid
join entitydetails on entitydetails.id = contacttyperolemap.ContactTypeID
join contact on contact.contactTypeID = entitydetails.id
where contacttyperolemap.contactTypeID = contactroleid
order by contact.id;
CREATE temporary TABLE tmp(
ID double ,
userid double ,
roleid double ,
permissionid double
);
END
stored procedures result is
uid rid pid
2 1 5
2 1 2
2 1 3
2 1 4
2 1 1
23 1 4
23 1 1
23 1 5
23 1 2
23 1 3
26 1 4
26 1 1
26 1 5
26 1 2
26 1 3
I want to insert this data inside userpermission table
schema is
id uid rid pid
1 10 2 1
Looks like you need to create a view instead of a stored procedure for the first 3 rows. Then in a separate query you can query any columns from that view and join that data with whatever other data you want from other tables. Hopefully I read the question right. Heres an article on creating views: https://msdn.microsoft.com/en-us/library/ms187956.aspx
Use INSERT ... SELECT command to fill target table.
And, your temp table shows empty result, because you have not filled it.

Error 126 - Incorrect key file for table - 4,8 GB table size

I want to remove duplicates from a table that contains 280.717.107 entries.
The table consist in 3 fields (no primary key) user_id, from_user_id, value.
At some point there are some repetitive entries that I want to remove.
Let's say something like this:
user_id from_user_id value
1 2 4
2 2 4
3 2 4
1 2 4 #duplicate
5 2 4
8 2 4
9 2 4
9 2 4 #duplicate
My table is having 4,8 GB size (I dumped it)
So I went to the server (not phpMyAdmin) and in MySQL I did the following:
CREATE TABLE temp_table SELECT DISTINCT * FROM my_table;
At one point I get this error message :
"Error 126 - Incorrect key file for table"
Some people say that this message might be because the memory is full.
My question is can I bypass this memory crash somehow and create this new table with my distinct entries?
You could try doing it in batches by applying a filter like
where user_id <= 1000
and increasing the value each time. So the next would be
where user_id > 1000 and user_id <= 2000
Like you mentioned in your comment, limit and offset would also work.

MS Access 2007 Rows to columns in recordset

I have a table which is like a questionnaire type ..
My original table contains 450 columns and 212 rows.
Slno is the person's id who answer the questionaire .
SlNo Q1a Q1b Q2a Q2b Q2c Q2d Q2e Q2f .... Q37c <450 columns>
1 1
2 1 1
3 1
4 1 1
5 1
I have to do analysis for this data , eg Number of persons who is male (Q1a) and who owns a boat (Q2b) i.e ( select * from Questionnaire where Q1a=1 and Q2b=1 ).. etc .. many more combinations are there ..
I have designed in MS access all the design worked perfectly except for a major problem ( Number of table columns is restricted to 255 ).
To be able to enter this into access table i have inserted in as 450 rows and 212 columns (now am able to enter this into access db). Now while fetching the records i want the record set to transpose the results into the form that i wanted so that i do not have to change my algorithm or logic .... How to achieve this with the minimum changes ? This is my first time working with Access Database
You might be able to use a crosstab query to generate what you are expecting. You could also build a transpose function.
Either way, I think you'll stil run into the 255 column limit and MS Access is using temporary table, etc.
However, I think you'll have far less work and better results if you change the structure of your table.
I assume that this like a fill-in-the-bubble questionnaire, and it's mostly multiple choice. In which case instead of recording the result, I would record the answer for the question
SlNo Q1 Q2
1 B
2 B
3 A
4 A C
5 A
Then you have far fewer columns to work with. And you query for where Q1='A' instead of Q1a=1.
The alternative is break the table up into sections (personal, career, etc.) and then do a join, and only show the column you need (so as not to exceed that 255 column limit).
An way to do this that handles more questions is have a table for the person, a table for the question, and a table for the response
Person
SlNo PostalCode
1 90210
2 H0H 0H0
3
Questions
QID, QTitle, QDesc
1 Q1a Gender Male
2 Q1b Gender Female
3 Q2a Boat
4 Q2b Car
Answers
SlNo QID Result
1 2 True
1 3 True
1 4 True
2 1 True
2 3 False
2 4 True
You can then find the question takers by selecting Persons from a list of Answers
select * from Person
where SlNo in (
select SlNo from Answers, Questions
where
questions.qid = answers=qid
and
qtitle = 'Q1a'
and
answers.result='True')
and SlNo in (
select SlNo from Answers, Questions
where
questions.qid = answers=qid
and
qtitle = 'Q2a'
and
answers.result='True')
I finally got the solutions
I created two table one having 225 columns and the other having 225 column
(total 450 columns)
I created a SQL statement
select count(*) from T1,T2 WHERE T1.SlNo=T2.SlNo
and added the conditions what i want
It is coming correct after this ..
The database was entered wrongly by the other staff in the beginning but just to throw away one week of work was not good , so had to stick to this design ... and the deadly is next week .. now it's working :) :)

MySQL: get differences of each sorted column in set of rows

Here is a simple scenario with table characters:
CharacterName GameTime Gold Live
Foo 10 100 3
Foo 20 100 2
Foo 30 95 2
How do I get this output for the query SELECT Gold, Live FROM characters WHERE name = 'Foo' ORDER BY GameTime:
Gold Live
100 3
0 -1
-5 0
using MySQL stored procedure (or query) if it's even possible? I thought of using 2 arrays like how one would normally do in a server-side language, but MySQL doesn't have array types.
While I'm aware it's probably easier to do in PHP (my server-side langauge), I want to know if it's possible to do in MySQL, just as a learning material.
Do you have an ID on your Table.
GameID CharacterName GameTime Gold Live
----------- ------------- ----------- ----------- -----------
1 Foo 10 100 3
2 Foo 20 100 2
3 Foo 30 95 2
If so you could do a staggered join onto itself
SELECT
c.CharacterName,
CASE WHEN c_offset.Gold IS NOT NULL THEN c.Gold - c_offset.Gold ELSE c.Gold END AS Gold,
CASE WHEN c_offset.Live IS NOT NULL THEN c.Live - c_offset.Live ELSE c.Live END AS Live
FROM Characters c
LEFT OUTER JOIN Characters c_offset
ON c.GameID - 1 = c_offSet.GameID
ORDER BY
c.GameTime
Essentially it joins each game row to the previous game row and does a diff between the values. That returns the following for me.
CharacterName Gold Live
------------- ----------- -----------
Foo 100 3
Foo 0 -1
Foo -5 0
One possible solution using a temporary table:
CREATE TABLE characters_by_gametime (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
gold INTEGER,
live INTEGER);
INSERT INTO characters_by_gametime (gold, live)
SELECT gold, live
FROM characters
ORDER BY game_time;
SELECT
c1.id,
c1.gold - IFNULL(c2.gold, 0) AS gold,
c1.live - IFNULL(c2.live, 0) AS live
FROM
characters_by_gametime c1
LEFT JOIN characters_by_gametime c2
ON c1.id = c2.id + 1
ORDER BY
c1.id;
Of course Eoin's solution is better if your id column follows the order you want in the output.