MySQL: Count Columns Per Row - mysql

I just want to know if counting columns is possible as you're counting rows without calling each column name. For example:
SELECT COUNT(FOUND COLUMNS) AS counted FROM table WHERE a_value EXISTS IN COLUMNS
/*
The same as this specified one. This is working but I'm
looking for another approach without calling each column name.
SELECT (IF(col1="Y",1,0) + IF(col2="Y",1,0)) as counted FROM table
*/
Which I wish will throw results per row like:
| counted |
|-----------|
| 2 |
| 1 |
| 0 |
IS THAT POSSIBLE? If yes, how?

SELECT COUNT(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG = 'database' AND TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'table'
Try this it will work.

I think you are looking for that
THE SCHEMA
CREATE TABLE `numbers`( `col1` INT, `col2` INT, `col3` INT, `col4` INT );
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('0', '0', '0', '6');
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('1', '0', '0', '9');
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('4', '1', '0', '2');
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('9', '5', '1', '3');
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('5', '0', '6', '4');
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('2', '0', '1', '6');
INSERT INTO `numbers` (`col1`, `col2`, `col3`, `col4`) VALUES ('8', '5', '6', '7');
COUNT THE VALUE '0' OF EACH ROW
SELECT (c1+c2+c3+c4) AS counted FROM
(
SELECT
CASE WHEN col1 = 0 THEN 1 ELSE 0 END AS c1,
CASE WHEN col2 = 0 THEN 1 ELSE 0 END AS c2,
CASE WHEN col3 = 0 THEN 1 ELSE 0 END AS c3,
CASE WHEN col4 = 0 THEN 1 ELSE 0 END AS c4
FROM numbers
) AS temp_count
/RESULT/
counted
3
2
1
0
1
1
0
COUNT THE VALUE '7' OF EACH ROW
SELECT (c1+c2+c3+c4) AS counted FROM
(
SELECT
CASE WHEN col1 = 7 THEN 1 ELSE 0 END AS c1,
CASE WHEN col2 = 7 THEN 1 ELSE 0 END AS c2,
CASE WHEN col3 = 7 THEN 1 ELSE 0 END AS c3,
CASE WHEN col4 = 7 THEN 1 ELSE 0 END AS c4
FROM numbers
) AS temp_count
So you must replace the value of col1 = 7,col2 = 7,col3 = 7,col4 = 7, if you want check the others value.

Related

Verify migrated records in SQL Server tables

I have a scenario where I transferred data from table t1 to t2. Not every record was transferred. I want to figure out which IDs were completely transferred. For example, I have a subset of data in which both IDs 23 and 25 has 5 records each with different section and subsections. Since only 2 records from ID 23 were transferred to t2, I do not want them in my resultant query. Whereas, for ID 25, all the records were transferred to t2. So, I want it to reflect in my result.
I got this far
select *
from t2
where exists (select * from t1
where t1.id = t2.id
and t1.section = t2.section
and t1.sub = t2.sub
group by id)
Table 1
id section sub
----------------
23 1 9
23 1 10
23 2 2
23 3 2
23 3 3
24 1 9
24 1 10
24 2 2
24 3 2
24 3 3
25 1 9
25 1 10
25 2 2
25 3 2
25 3 3
Table 2
id section sub
----------------
23 1 9
23 1 10
25 1 9
25 1 10
25 2 2
25 3 2
25 3 3
Required result:
id section sub
---------------
25 1 9
25 1 10
25 2 2
25 3 2
25 3 3
Code to create tables
CREATE TABLE t1
(
id varchar(3),
section varchar(4),
sub varchar(2)
)
CREATE TABLE t2
(
id varchar(3),
section varchar(4),
sub varchar(2)
)
INSERT INTO t1 (id, section, sub)
VALUES ('23', '1', '9')
INSERT INTO t1 (id, section, sub)
VALUES ('23', '1', '10')
INSERT INTO t1 (id, section, sub)
VALUES ('23', '2', '2')
INSERT INTO t1 (id, section, sub)
VALUES ('23', '3', '2')
INSERT INTO t1 (id, section, sub)
VALUES ('23', '3', '3')
INSERT INTO t1 (id, section, sub)
VALUES ('24', '1', '9')
INSERT INTO t1 (id, section, sub)
VALUES ('24', '1', '10')
INSERT INTO t1 (id, section, sub)
VALUES ('24', '2', '2')
INSERT INTO t1 (id, section, sub)
VALUES ('24', '3', '2')
INSERT INTO t1 (id, section, sub)
VALUES ('24', '3', '3')
INSERT INTO t1 (id, section, sub)
VALUES ('25', '1', '9')
INSERT INTO t1 (id, section, sub)
VALUES ('25', '1', '10')
INSERT INTO t1 (id, section, sub)
VALUES ('25', '2', '2')
INSERT INTO t1 (id, section, sub)
VALUES ('25', '3', '2')
INSERT INTO t1 (id, section, sub)
VALUES ('25', '3', '3')
INSERT INTO t2 (id, section, sub)
VALUES ('23', '1', '9')
INSERT INTO t2 (id, section, sub)
VALUES ('23', '1', '10')
INSERT INTO t2 (id, section, sub)
VALUES ('25', '1', '9')
INSERT INTO t2 (id, section, sub)
VALUES ('25', '1', '10')
INSERT INTO t2 (id, section, sub)
VALUES ('25', '2', '2')
INSERT INTO t2 (id, section, sub)
VALUES ('25', '3', '2')
INSERT INTO t2 (id, section, sub)
VALUES ('25', '3', '3')
You can try the following, just need to count the number of each ID in t2 and compare that to the same count in t1 where they are the same:
select id,section,sub from (
select *, Count(*) over(partition by id) c
from t2
)t
where c=(
select Count(*)
from t1
where t1.id=t.id
group by t1.id
)

Maria DB - update row with value of previous row + constant

I have table called dobridol with several column.
CREATE TABLE IF NOT EXISTS `dobridol` (
`id` int(6) unsigned NOT NULL,
`dt` varchar(200) NOT NULL,
`p2` int(6) NOT NULL,
`p6` int(6) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `dobridol` (`id`, `dt`, `p2`,`p6`) VALUES
('1', '2021-02-28 23:50:00', '100', '600'),
('2', '2021-02-28 23:55:00', '200', '700'),
('3', '2021-03-01 00:00:00', '300', '800'),
('4', '2021-03-01 00:05:00', '400', '900'),
('5', '2021-03-01 00:10:00', '400', '900'),
('6', '2021-03-01 00:15:00', '400', '900'),
('7', '2021-03-01 00:20:00', '500', '1000'),
('8', '2021-03-01 00:25:00', '600', '1100');
The table has values for January and March also.
I want to be able to UPDATE table like that:
I select period as month, then I add constant value (in this case I added 39) to p6 ONLY WHEN p2 value is different than previous row p2.
If this is the case I have to add 39 to PREVIOUS row p6 value.
update dobridol join
(select tt.*,
sum(case when p2 <> prev_p2 then 1 else 0 end) over (order by dt) as cnt
from (select tt.*,
lag(p2) over (order by dt) as prev_p2
from dobridol tt
) tt
) tt
on tt.id = dobridol.id
set dobridol.p6 = cnt * 39 + <PREVIOUS_ROW_p6_VALUE_HAS_TO_BE_HERE>
where cnt > 0
The query should look-like this but I have to replace this <PREVIOUS_ROW_VALUE_HAS_TO_BE_HERE> with the right syntax of picking last row p6. How can I pick it?
Also where to add clause
dobridol.dt BETWEEN '2021-03-01' AND '2021-03-30'
in the SQL query?
If I understand correctly, you can use lag():
update dobridol join
(select tt.*,
lag(p6) over (order by dt) as prev_p6,
sum(case when p2 <> prev_p2 then 1 else 0 end) over (order by dt) as cnt
from (select tt.*,
lag(p2) over (order by dt) as prev_p2
from dobridol tt
) tt
) tt
on tt.id = dobridol.id
set dobridol.p6 = tt.cnt * 39 + tt.prev_p6
where cnt > 0 ;
Here is a db<>fiddle.

MySQL pivoting not working as expected

Schema:
DROP TABLE IF EXISTS `questions_tags`;
CREATE TABLE `questions_tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag_id` int(11) NOT NULL,
`question_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `questions_tags` VALUES ('1', '1', '1');
INSERT INTO `questions_tags` VALUES ('2', '2', '1');
INSERT INTO `questions_tags` VALUES ('3', '3', '1');
INSERT INTO `questions_tags` VALUES ('4', '4', '1');
INSERT INTO `questions_tags` VALUES ('5', '5', '1');
INSERT INTO `questions_tags` VALUES ('6', '2', '2');
Data:
id tag_id question_id
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 2 2
What I've tried:
SELECT
question_id,
CASE WHEN tag_id = 1 THEN 'TAG1' END AS FirstTag,
CASE WHEN tag_id = 2 THEN 'TAG2' END AS SecondTag,
CASE WHEN tag_id = 3 THEN 'TAG3' END AS ThirdTag,
CASE WHEN tag_id = 4 THEN 'TAG4' END AS FourthTag,
CASE WHEN tag_id = 5 THEN 'TAG5' END AS FifthTag
FROM questions_tags
GROUP BY question_id;
Current Output:
Expected Output:
Is there something that I misjudged about Pivoting? Any help is appreciated.
Use aggregation on the case expressions.
SELECT
question_id,
max(CASE WHEN tag_id = 1 THEN 'TAG1' END) AS FirstTag,
max(CASE WHEN tag_id = 2 THEN 'TAG2' END) AS SecondTag,
max(CASE WHEN tag_id = 3 THEN 'TAG3' END) AS ThirdTag,
max(CASE WHEN tag_id = 4 THEN 'TAG4' END) AS FourthTag,
max(CASE WHEN tag_id = 5 THEN 'TAG5' END) AS FifthTag
FROM questions_tags
GROUP BY question_id;

How to ignore next duplicated row?

I need your help!
I have a table:
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`res` varchar(255) DEFAULT NULL,
`value` int(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- Records of table
INSERT INTO `table` VALUES (1, 'gold', 44);
INSERT INTO `table` VALUES (2, 'gold', 44);
INSERT INTO `table` VALUES (3, 'gold', 45);
INSERT INTO `table` VALUES (4, 'gold', 46);
INSERT INTO `table` VALUES (5, 'gold', 44);
INSERT INTO `table` VALUES (6, 'gold', 44);
INSERT INTO `table` VALUES (7, 'gold', 44);
INSERT INTO `table` VALUES (8, 'gold', 47);
i need to make SELECT request which will ignored next or previous duplicated rows and i receive data like this:
- gold:44 (ignored 1 record)
- gold:45
- gold:46
- gold:44 (ignored 2 records)
- gold:47
there is no object which duplicated record will ignore (first,second,last).
(i tried to use group by value or distinct but this way removes other records with same value)
You can solve this with a gaps and islands solution.
- Normally that involves ROW_NUMBER() which is not present in MySQL
- The solution below mimics ROW_NUMBER() with variables and ORDER BY
Link to example : http://sqlfiddle.com/#!9/32e72/12
SELECT
MIN(id) AS id,
res,
value
FROM
(
SELECT
IF (#res = res AND #val = value, #row := #row + 1, #row := 1) AS val_ordinal,
id AS id,
res_ordinal AS res_ordinal,
#res := res AS res,
#val := value AS value
FROM
(
SELECT
IF (#res = res , #row := #row + 1, #row := 1) AS res_ordinal,
id AS id,
#res := res AS res,
#val := value AS value
FROM
`table`,
(
SELECT #row := 0, #res := '', #val := 0
)
AS initialiser
ORDER BY
res, id
)
AS sequenced_res_id,
(
SELECT #row := 0, #res := '', #val := 0
)
AS initialiser
ORDER BY
res, value, id
)
AS sequenced_res_val_id
GROUP BY
res,
value,
res_ordinal - val_ordinal
ORDER BY
MIN(id)
;
If I add res_ordinal, val_ordinal and res_ordinal - val_ordinal to your data, it can be seen that you can now differentiate between the two sets of 44
GROUP
INSERT INTO `table` VALUES ('1', 'gold', '44'); 1 - 1 = 0 (Gold, 44, 0)
INSERT INTO `table` VALUES ('2', 'gold', '44'); 2 - 2 = 0
INSERT INTO `table` VALUES ('3', 'gold', '45'); 3 - 1 = 2 (Gold, 45, 2)
INSERT INTO `table` VALUES ('4', 'gold', '46'); 4 - 1 = 3 (Gold, 46, 3)
INSERT INTO `table` VALUES ('5', 'gold', '44'); 5 - 3 = 2 (Gold, 44, 2)
INSERT INTO `table` VALUES ('6', 'gold', '44'); 6 - 4 = 2
INSERT INTO `table` VALUES ('7', 'gold', '44'); 7 - 5 = 2
INSERT INTO `table` VALUES ('8', 'gold', '47'); 8 - 1 = 7 (Gold, 47, 7)
NOTE: According to your data I could use id instead of making my own res_ordinal. doing it this way, however, copes with gaps in the id sequence and having multiple different resources. This means that in the following example the two golds are considered to be duplicates of each other...
1 Gold 44 1 - 1 = 0 (Gold, 44, 0)
2 Poop 45 1 - 1 = 0 (Poop, 45, 0)
3 Gold 44 2 - 2 = 0 (Gold, 44, 0) -- Duplicate
4 Gold 45 3 - 1 = 2 (Gold, 44, 2)
select t1.*
from `table` t1
where not exists ( select 1
from `table` t2
where t1.id = 1+t2.id
and t1.res = t2.res
and t1.value = t2.value
);
works fine
Use the DISTINCT clause to select unique rows like so:
SELECT DISTINCT res, value FROM table
Use Select DISTINCT res, value FROM table ... to avoid redundancy

sum column counts for two different values

i have a column that can hold 6 values (1,2,3,A,B,C)
i can count(*) them so it looks like this
select mycol, count(*) as ttl from mytable group by mycol;
mycol ttl
1 46
2 53
3 10
A 5
B 4
C 2
but i want to sum the 1s and the As, and the 2s and the Bs like this
mycol total
var1 51
var2 57
var3 12
will a case statement work for this? like case 1 or A then treat them the same
Yes, a case statement will work for this:
select (case when mycol in ('1', 'var1') then 'var1'
when mycol in ('2', 'var2') then 'var2'
when mycol in ('3', 'var3') then 'var3'
end),
sum(ttl) as Total
from mytable t
group by (case when mycol in ('1', 'var1') then 'var1'
when mycol in ('2', 'var2') then 'var2'
when mycol in ('3', 'var3') then 'var3'
end);
EDIT:
If you just have the data with multiple rows for each value:
select (case when mycol in ('1', 'var1') then 'var1'
when mycol in ('2', 'var2') then 'var2'
when mycol in ('3', 'var3') then 'var3'
end),
count(*) as Total
from mytable t
group by (case when mycol in ('1', 'var1') then 'var1'
when mycol in ('2', 'var2') then 'var2'
when mycol in ('3', 'var3') then 'var3'
end);