Dynamically creating columns from row data using Select in Bigquery - mysql

Background
I want to rename my case statement in sql select statement dynamically.
Eg:
SELECT (case when id= x.id then x.sums end) x.id
as (select id,count(*) sums from table
group by id) x
what i want the output is list of columns created ,with Labels as distinct id's from "id" column.
However,this variable x.id is not dynamically outputing values,rather i get output a single column x.id.
Eg:
Columns in table...
id---c1----c2
1----x1---x2
2----x2----x3
3----x4----x5
columns expected after running query...
1-----2----3
but actual o/p column is::
x.id
Query
Any ideas,how to generate columns dynamically using select query,please correct me ,if i am wrong.

Below is for BigQuery!
Please note: your expectations about output column names are not correct!
Column name cannot start with digit - so in below example - i will be using id_1, id_2 and id_3 instead of 1, 2 and 3
SELECT
SUM(CASE WHEN id = 1 THEN 1 END) AS id_1,
SUM(CASE WHEN id = 2 THEN 1 END) AS id_2,
SUM(CASE WHEN id = 3 THEN 1 END) AS id_3
FROM YourTable
Above example assumes you know in advance your IDs and there are very few of them so it is not a big deal to write manually few numbers of lines with SUM(...) for each id
If this is not a case - you can first generate above query programmatically by running below query
SELECT 'SELECT ' +
GROUP_CONCAT_UNQUOTED(
'SUM(CASE WHEN id = ' + STRING(id) + ' THEN 1 END) AS id_' + STRING(id)
)
+ ' FROM YourTable'
FROM (
SELECT id FROM (
SELECT * FROM YourTable GROUP BY id ORDER BY id
)
as a result - you will get string like below
SELECT SUM(CASE WHEN id = 1 THEN 1 END) AS id_1,SUM(CASE WHEN id = 2 THEN 1 END) AS id_2,SUM(CASE WHEN id = 3 THEN 1 END) AS id_3 FROM YourTable
So, now just copy it and paste into Query Editor and run it
you can see similar example here - https://stackoverflow.com/a/36623258/5221944

Related

How to simulate a N-dimension INTERSECT with generic SQL

Here is an example of 2 extract from the same table:
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=2 AND VALUE LIKE '%TATA%';
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=4 AND VALUE LIKE '%TUTU%';
They give 2 sets of source_id.
Right. Now if I need an intersect of those with MySQL (where INTERSECT does not exist) I found this way:
SELECT DISTINCT source_id
FROM (
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=2 AND VALUE LIKE '%TATA%'
) t1
INNER JOIN (
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id=4 AND VALUE LIKE '%TUTU%'
) t2
USING (source_id);
but what if I need to do this from N sets ?
I can't find a solution + I'm worried about the perf. of doing it this way
You can use a grouping approach. Depending on what indexes you have available this might work out better.
SELECT source_id
FROM table_cust_string_value
WHERE cust_string_id IN ( 2, 4 )
GROUP BY source_id
HAVING MAX(CASE WHEN cust_string_id = 2 AND VALUE LIKE '%TATA%' THEN 1 END) = 1
AND MAX(CASE WHEN cust_string_id = 4 AND VALUE LIKE '%TUTU%' THEN 1 END) = 1

How can I get the multiple columns in a single row using MySQL?

I want combine mutiple rows columns as single record in MySQL
For eg: Actual Data
--------------------------------------------------------------
id name Loantype Amount
--------------------------------------------------------------
1 ABC 1 500000
2 ABC 2 3500000
3 XYZ 1 250000
4 XYZ 2 2500000
I tried with the following query
SELECT
id,
(
CASE Loantype
WHEN 1 THEN Amount
ELSE NULL
END
) AS PersonalLoan,
(
CASE Loantype
WHEN 2 THEN Amount
ELSE NULL
END
) AS HomeLoan
FROM
customer
WHERE
name = 'ABC'
but result comes as below
--------------------------------------------------------------
id name PersonalLoan HomeLoan
--------------------------------------------------------------
1 ABC 500000 NULL
1 ABC NULL 2500000
Expected Result set
--------------------------------------------------------------
id name PersonalLoan HomeLoan
--------------------------------------------------------------
1 ABC 500000 3500000
You can self-join the table so that you will be able to combine the 2 kinds of loans into single row:
SELECT t1.id, t1.name, t1.amount AS personal, t2.amount AS home
FROM customer AS t1
LEFT JOIN customer AS t2 ON t1.name = t2.name AND t2.loantype = 2
WHERE t1.loantype = 1
If you are looking for just 1 user - you can speedup the query by limiting the size of the JOIN:
SELECT t1.id, t1.name, t1.amount AS personal, t2.amount AS home
FROM (SELECT * FROM customer WHERE name = "ABC" AND loantype = 1) AS t1
LEFT JOIN customer AS t2 ON t1.name = t2.name AND t2.loantype = 2
Note that generally speaking you shouldn't denormalize data in SQL (e.g. converting rows to columns: SQL is row-oriented, not column-oriented) - I assume this is to simplify display logic - just be careful of using queries like this when you want to pass meaningful data to other parts of the database rather than directly to the user.
You need to GROUP BY first.
You can also simplify your CASE expressions:
ELSE NULL is always implicit and if the CASE WHEN expression is an equality comparison then you can use the simpler switch-style syntax.
So CASE WHEN a = b THEN c ELSE NULL END can be simplified to CASE a WHEN b THEN c END.
I've added COALESCE so the query will return 0 for the SUM aggregates if there are no matching rows instead of NULL. Note that COUNT (unlike SUM) generally doesn't need to be wrapped in a COALESCE (though I forget precisely how MySQL handles this - it also depends on what version of MySQL you're using and what strict-mode and ANSI/ISO-compliance options are enabled).
Note that the database design you posted seems to allow the same customer.name to have multiple loans of the same loantype.
You can avoid this by adding a UNIQUE CONSTRAINT or UNIQUE INDEX or use a Composite Primary Key:
CREATE UNIQUE INDEX UX_name_loantype ON customer ( name, loantype )
To prevent those rows from causing issues in this query, this uses a SUM and a COUNT to make it clear to readers that the data is an aggregate over multiple rows:
SELECT
name,
COUNT( CASE Loantype WHEN 1 THEN 1 END ) AS CountPersonalLoans,
COALESCE( SUM( CASE Loantype WHEN 1 THEN Amount END ), 0 ) AS SumPersonalLoans,
COUNT( CASE Loantype WHEN 2 THEN 1 END ) AS CountHomeLoans,
COALESCE( SUM( CASE Loantype WHEN 2 THEN Amount END ), 0 ) AS SumHomeLoans
FROM
customer
GROUP BY
name
To maximise query code reuse if you want to filter by name then convert this to a VIEW - or if it's a one-off then make it a CTE query, like so:
WITH aggs AS (
SELECT
name,
COUNT( CASE Loantype WHEN 1 THEN 1 END ) AS CountPersonalLoans,
COALESCE( SUM( CASE Loantype WHEN 1 THEN Amount END ), 0 ) AS SumPersonalLoans,
COUNT( CASE Loantype WHEN 2 THEN 1 END ) AS CountHomeLoans,
COALESCE( SUM( CASE Loantype WHEN 2 THEN Amount END ), 0 ) AS SumHomeLoans
FROM
customer
GROUP BY
name
)
SELECT
name,
CountPersonalLoans,
SumPersonalLoans,
CountHomeLoans,
SumHomeLoans
FROM
aggs
WHERE
name = 'ABC'
ORDER BY
name

Mysql create table with sums of nulls and not nulls

Scenario: I am trying to create an output matrix where I have all the columns names (fields) of a source table in the first column, followed by the sum of all Null values of that original field column.
Ex:
Original Table:
Id1 Code Range
aa 33 null
ab 12 001
ac 53 001
ad null null
null 36 002
Wanted output:
Fields #ofnull #ofnonnull
Id1 1 4
Code 1 4
Range 2 3
For this I have a code that retrieves the names and positions of all the columns in the original matrix, and a snippet which counts my nulls/nonnulls.
Issue: I have no idea how to string those together and get this output with a single query. I tried searching around, but most answers were regarding just counting the nulls, not on the process on inputting a list of columns to the query.
Question: Is it possible to do this? or do I have to feed the query each column name manually?
Code so far:
select
`ordinal_position`,
`column_name`,
from `dev1`.`info`
where `table_schema` = 'dev1'
and `table_name` = 'data1'
order by `ordinal_position`;
select
count(1)
from `dev1`.`data1`
where Id1 is null;
-- where Id1 is not null;
One approach uses a series of unions:
SELECT
'Id1' AS Fields,
COUNT(CASE WHEN Id1 IS NULL THEN 1 END) AS NoNull,
COUNT(Id1) AS NoNonNull
FROM yourTable
UNION ALL
SELECT 'Code', COUNT(CASE WHEN Code IS NULL THEN 1 END), COUNT(Code)
FROM yourTable
UNION ALL
SELECT 'Range', COUNT(CASE WHEN `Range` IS NULL THEN 1 END), COUNT(`Range`)
FROM yourTable;
Demo
You can try using UNION ALL
SELECT
field,
COUNT(CASE WHEN val IS NULL THEN 1 END) AS `#ofnull`,
COUNT(CASE WHEN val IS NOT NULL THEN 1 END) AS `#ofnotnull`
FROM
(
SELECT 'Id1' AS field, Id1 AS val FROM yourTable
UNION ALL
SELECT 'Code', Code FROM yourTable
UNION ALL
SELECT 'Range', `Range` FROM yourTable
) a
GROUP BY field;

multiple rows into columns mysql

Hi I am trying to create a mysql query that will convert multiple rows in a table to unique columns
The data I have is as follows:
The table I would like to see is as follows:
GEID|Username|First Name|Last Name|Email|Country|Dealer Code
The statement which could be used is
UPDATE table_name
SET column1 = value 1 , column 2 = value 2 ...
Where condition;
Sorry but my SQL isn't the best but hope the statement helps
This is a real pain, because you don't have an id identifying groups that are the same. In other words, you are missing the entity id.
I think you can construct one by counting the number of GEID values before any given row. The rest is just aggregation:
select max(case when fieldname = 'GEID' then fieldData end) as GEID,
max(case when fieldname = 'Username' then fieldData end) as Username,
. . .
from (select t.*,
(select count(*) from t t2 where t2.id <= t.id and t2.fieldName = 'GEID'
) as grp
from t
) t
group by grp;

Change an ID with a String on SQL Query view

I have an SQL query to retrieve a few columns of a table and export them on a CSV file. However, one column use an ID (integer number). Is there any way to include something in SQL query and replace the IDs with specific strings?
For example:
If ID = 1 then replace it with "Dog"
If ID = 2 then replace it with "Cat"
If ID = 3 then replace it with "Apple"
I have only four IDs so, it will not be huge.
Here is what I have done until now to retrieve the columns I want
SELECT col_id, check_in, start_hour, price_total, email FROM reservations LIMIT 10
SELECT case when col_id = 1 then 'Dog'
when col_id = 2 then 'Cat'
when col_id = 3 then 'Apple'
end as id,
check_in, start_hour, price_total, email
FROM reservations
LIMIT 10
You could use case/when/then like this:
select case when ID = 1 then 'one' else 'two' end from reservations