Query for counting in MySQL [duplicate] - mysql

This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
Closed 8 years ago.
I'm pretty sure it is a very simple question but I'm new to mysql so I would appreciate some help..
I would like to use the following table in order to count how many times each item is registered for each ID, and generate a new table from there with columns corresponding to each distinct item (a count vector for each ID). So for example, having this:
ID ITEM
-----------------
0001 345
0001 345
0001 120
0002 567
0002 034
0002 567
0003 567
0004 533
0004 008
I want this:
ID 008 034 120 345 533 567
----------------------------------------------
0001 0 0 1 2 0 0
0002 0 1 0 0 0 2
0003 0 0 0 0 0 1
0004 1 0 0 0 0 0
Thank you

Slightly different from what you asked for, but easier on the complex SQL;
SELECT id, item,
(SELECT COUNT(item) FROM Table1 WHERE id=a.id AND item=a.item) cnt
FROM (SELECT DISTINCT a.id,b.item FROM Table1 a, Table1 b) a
ORDER BY id, item;
This will create a row per element instead of per customer, a'la;
ID ITEM CNT
1 8 0
1 34 0
1 120 1
1 345 2
1 533 0
1 567 0
2 8 0
2 34 1
...
The query above isn't very nice to MySQLs optimizer, so will probably perform slowly (an index on id/item may help). Much easier on the database is if you don't care about the zero columns;
SELECT id, item, COUNT(item) cnt
FROM Table1
GROUP BY id, item
ORDER BY id, item;
ID ITEM CNT
1 120 1
1 345 2
2 34 1
2 567 2
3 567 1
...
Both mean a little bit more work on the Python side, but avoid a lot of complexity for the database.
An SQLfiddle with both in action.

Related

Update the mysql field according to the sorting

a simple task, but I can't figure it out. There is a Table:
id
name
sum
place
1
Alex
210
0
2
Bob
250
0
3
Sam
190
0
4
Bill
290
0
5
Jack
210
0
I need to UPDATE the PLACE
according to the maximum SUM and then the id
Those are the request :
SELECT id, name, sum, place FROM tableORDER BYsumDESC,id ASC;
According to this request, update the semi PLACE from 1++
Those places 1, 2, 3 and further throughout the table
Like this:
id
name
sum
place
1
Alex
210
3
2
Bob
250
2
3
Sam
190
5
4
Bill
290
1
5
Jack
210
4
SET #n_place := 0;
UPDATE `table` SET `place` = #n_place := #n_place + 1 ORDER BY `sum` DESC, `id` ASC;

Query to get rows with two consecutive zeros in a column

I have a data set:
sid name sub marks subid
11 kittu eng 55 1
11 kittu math 0 2
11 kittu sci 0 3
12 bunnu eng 0 1
12 bannu math 44 2
12 bannu sci 0 3
13 siva eng 0 1
13 siva math 0 2
13 siva sci 88 3
and I want to get output like this (which have consecutive zero marks):
11 kittu
13 siva
SELECT a row from T WHERE exists a row another with same sid and a lower subid sequentially and both rows have zero marks.
Then Do a DISTINCT just in case there are more than qualifying condition so you don't get duplicates.
SELECT DISTINCT sid,name
FROM t
WHERE EXISTS (SELECT 1 FROM T T2
WHERE T2.marks = 0
AND t.marks = 0
AND T2.sid = T.sid
AND T2.subid = t.subid + 1)
sqlfiddle

Increment Group Number based on row value SQL Server 2008

I have two tables that aren't really associated, but need to be combined. So I'm using union all on the two tables. The unioned tables are ordered by date, so rows from one table are dispersed among rows from the other table. What I need to do is get a running count of a column so I can group elements.
To explain further, table A holds dates of when a container is emptied, while table B holds daily entries for content of the container. I need to union the two tables so I have one table where I can get the sum of the information for a container before the container is emptied.
So I need something like this:
Table A:
Location_ID Empty Date
123 3/2/13
123 3/10/13
123 4/1/13
Table B:
PSI Entry Date Location_ID
120 2/28/13 123 (same for all)
130 3/1/13
100 3/8/13
110 3/9/13
200 3/18/13
180 3/20/13
So the unioned table after some magic would look like:
Table C...:
Location_ID Date PSI Emptied
123 2/28/13 120 0
123 3/1/13 130 0
123 3/2/13 null 1
123 3/8/13 100 0
123 3/9/13 110 0
123 3/10/13 null 1
123 3/18/13 200 0
123 3/20/13 180 0
123 4/1/13 null 1
What I need to do is have a grouping such that I can have a table like this
Table C_b
Location_ID Date PSI Emptied Group
123 2/28/13 120 0 1
123 3/1/13 130 0 1
123 3/2/13 null 1 1
123 3/8/13 100 0 2
123 3/9/13 110 0 2
123 3/10/13 null 1 2
123 3/18/13 200 0 3
123 3/20/13 180 0 3
123 4/1/13 null 1 3
How can I get that grouping in that way? I have to make it work in SQL Server 2008. I have tried using Count, and Rank, and Row_Number. But the problem with those is that it won't do a running count, it will just say the total count in each row.
Try this query:
DECLARE #MyTable TABLE(
EntryDate DATE NOT NULL,
Emptied BIT NOT NULL
);
INSERT INTO #MyTable (EntryDate,Emptied)
VALUES
('2013-01-01',0),
('2013-01-02',0),
('2013-01-03',1),
('2013-01-04',0),
('2013-01-05',0),
('2013-01-06',1),
('2013-01-07',0),
('2013-01-08',0),
('2013-01-09',1);
DECLARE #TableWithRowNum TABLE(
EntryDate DATE NOT NULL,
Emptied BIT NOT NULL,
RowNum INT PRIMARY KEY
);
INSERT INTO #TableWithRowNum (EntryDate,Emptied,RowNum)
SELECT crt.*,ROW_NUMBER() OVER(ORDER BY crt.EntryDate) AS RowNum
FROM #MyTable crt;
WITH RecCTE
AS(
SELECT
crt.EntryDate,
crt.Emptied,
crt.RowNum,
1 AS Grp
FROM #TableWithRowNum crt
WHERE crt.RowNum=1
UNION ALL
SELECT
crt.EntryDate,
crt.Emptied,
crt.RowNum,
CASE WHEN prev.Emptied=1 THEN prev.Grp+1 ELSE prev.Grp END
FROM #TableWithRowNum crt INNER JOIN RecCTE prev ON crt.RowNum=prev.RowNum+1
)
SELECT * FROM RecCTE
OPTION(MAXRECURSION 0); -- Default value for MAXRECURSION is 100
GO
Results:
EntryDate Emptied RowNum Grp
---------- ------- ------ ---
2013-01-01 0 1 1
2013-01-02 0 2 1
2013-01-03 1 3 1
2013-01-04 0 4 2
2013-01-05 0 5 2
2013-01-06 1 6 2
2013-01-07 0 7 3
2013-01-08 0 8 3
2013-01-09 1 9 3

MySQL SELECT statement to retrieve field value that is unique

For example
id staff_id skill_id mainskill
1 1 24 1
2 1 24 0
3 1 7 0
4 4 24 0
5 4 18 0
6 6 8 0
7 6 18 1
I would like the result to contain only the tuples with a skill_id that is present only once in all the data. In other words I want to retrieve the tuples containing the skill_ids that are only possessed by a single staff member.
And so the desired output is:
id staff_id skill_id mainskill
3 1 7 0
6 6 8 0
Thanks in advance :).
You can do it with GROUP BY and HAVING, like this:
SELECT
MAX(id) as id,
MAX(staff_id) as staff_id,
skill_id,
MAX(mainskill) as mainskill
FROM MyTable
GROUP BY skill_id
HAVING COUNT(1)=1

access query needed

I am looking for an access query, but a sql server 2008 could be sufficient as I can use a passthrough feature in access.
My data looks like this .
--------------------------------------------------------------
id nameid name score diff include
--------------------------------------------------------------
1 0001 SO 100 0 0
2 0001 SO 100 0 0
3 0001 SO 100 0 0
4 0001 SO 100 0 0
5 0001 SO 100 0 0
6 0001 SO 100 0 0
7 0002 MO 10 0 0
8 0002 MO 18 0 1
9 0002 MO 20 0 0
10 0002 MO 14 0 0
11 0002 MO 100 0 0
11 0002 MO 100 0 0
12 0003 MA 10 0 0
13 0003 MA 18 0 1
14 0003 MA 20 0 0
15 0003 MA 14 0 0
16 0003 MA 100 0 1
17 0003 MA 100 0 0
Now what i want is to go through each row and only select the rows where include = 1. THIS IS EASY however ,I don't want the entire row.. I want to select the "group". The group can be identified by the nameid (or name).
So for the above I want the following result:
--------------------------------------------------------------
id nameid name score diff include
--------------------------------------------------------------
7 0002 MO 10 0 0
8 0002 MO 18 0 1
9 0002 MO 20 0 0
10 0002 MO 14 0 0
11 0002 MO 100 0 0
11 0002 MO 100 0 0
12 0003 MA 10 0 0
13 0003 MA 18 0 1
14 0003 MA 20 0 0
15 0003 MA 14 0 0
16 0003 MA 100 0 1
17 0003 MA 100 0 0
Ask your table for row with include = 1.
Then join again with the table to have all the rows corresponding to the first query's nameid :
SELECT DISTINCT m.*
FROM myTable m
INNER JOIN myTable m2
ON m.nameid = m2.nameid
AND m2.include = 1
A join query will work better than an 'in' query for big amount of datas. You still need an index on the field 'nameid', and on 'include' could not hurt too.
An equivalent is with 'WHERE EXISTS' :
SELECT m.*
FROM myTable m
WHERE EXISTS
(
SELECT *
FROM myTable m2
WHERE m2.include = 1
AND m2.nameid = m.nameid
)
You could see the difference here :
Can an INNER JOIN offer better performance than EXISTS
And why you have to use a Where exists when you have a filter with a lot of IDs :
Difference between EXISTS and IN in SQL?
I think this query identifies the nameid values you want included in your main query.
SELECT DISTINCT nameid
FROM YourTable
WHERE include = 1;
If that is true, incorporate it as a subquery and use an INNER JOIN with YourTable to return only those rows for which a nameid value is associated with include = 1 ... in any row of the table.
SELECT id, nameid, name, score, diff, include
FROM
YourTable AS y
INNER JOIN (
SELECT DISTINCT nameid
FROM YourTable
WHERE include = 1
) AS q
ON y.nameid = q.nameid;
The Access query designer will probably substitute square brackets plus a dot in place of the parentheses enclosing the subquery.
SELECT id, nameid, name, score, diff, include
FROM
YourTable AS y
INNER JOIN [
SELECT DISTINCT nameid
FROM YourTable
WHERE include = 1
]. AS q
ON y.nameid = q.nameid;
You need a subquery - as follows:
SELECT *
FROM tablename
WHERE nameid IN
(
SELECT DISTINCT nameid
FROM tablename
WHERE include = 1
)
SELECT * FROM yourTable WHERE nameid IN (SELECT DISTINCT nameid FROM yourTable WHERE include=1)
What you do is, select every row, whose nameid is in your subquery.
The subquery selects the nameid for rows where include=1.