SQL: Selecting columns based on column value from another table - mysql

I have the following tables:
UserPrivileges:
+--------+------+------+------+
| UserID | Col1 | Col2 | Col3 |
+--------+------+------+------+
| 1 | 0 | 1 | 1 |
| 2 | 0 | 0 | 1 |
| 3 | 1 | 0 | 0 |
| 4 | 1 | 1 | 0 |
+--------+------+------+------+
Data:
+--------+------+------+------+
| DataID | Col1 | Col2 | Col3 |
+--------+------+------+------+
| 1 | A | B | C |
| 2 | D | E | F |
| 3 | G | H | I |
| 4 | J | K | L |
+--------+------+------+------+
My question at its simplest form doesn't has anything to do with the Data table but I just explain it anyways so that I might be doing it the wrong way.
How would I select the Column names from UserPrivileges based on the value ? So that I can use the result in another query to select only those columns.
Something along these lines:
SELECT (COLUMNS_NAME_QUERY_FROM_UserPrivileges(UserID='#')) WHERE DataID = '#' FROM Data
Or I don't mind a better way to manage user Privileges for specific columns.

The answer depends upon your requirements for the result. Do you require a result with a consistent set of columns, regardless of user privs? If so, you could set the disallowed values to null (or some other special value) using a IF clause, e.g.,
SELECT IF (p.col1 = 0 THEN NULL ELSE d.col1) AS col1,
IF (p.col2 = 0 THEN NULL ELSE d.col2) AS col2,
IF (p.col3 = 0 THEN NULL ELSE d.col3) AS col3
FROM Data d,
UserPrivileges p
WHERE p.userId = '#'
AND d.DataId = '#'
Of course, the "special value" could be a problem, since you need a value that would never appear in the data. If you needed to know that difference between a null because the real value is null vs. null because it is a prohibited column then you can't use null.
Another approach would have you simple include the privilege indicator for each column appear in the result, and let your business logic use that to determine which values are visible to the user.
A very different approach would have the result set to contain only the allowed columns. In this case you'll need to build your sql statement dynamically. I don't know if you are doing this in a stored procedure or in a host language, but the basic idea is something like this:
string sqlCmd = "SELECT "
+ (SELECT (FIELDS_NAME_QUERY(UserID='#')
FROM USER_PRIVILEGES
WHERE userid='#')
+ FROM data d
execute sqlCmd
"execute" meaning whatever you have available to execute a string as a sql command.
more after clarification by OP:
Ok, you need sql function that returns a string that looks like "colname1, colname2, ...". The following resembles what it would look like in sql server. syntax
create function
FIELDS_NAME_QUERY (#userid int)
begin
select col1, col2, col3... INTO #col1priv, #col2priv, #col3priv FROM userPrivileges WHERE UserId = #UserId
declare #result varhcar(60)
set #result = ''
if (#col1priv = 1) #result = 'col1'
if (#col2priv = 1) #result = #result + ' ,col2'
if (#col3priv = 1) #result = #result + ' ,col3'
return #result
end

have not tried it, but something like this should work
SELECT (SHOW COLUMNS FROM table WHERE expr) FROM data WHERE DataID = '#'
Check this post for details - How can I get column names from a table in Oracle?
Let us know how you solve this...

Related

Select column names [duplicate]

I am trying to make a query in mysql to get any column which has a particular value for one specific row.
In Mysql we can get rows based upon any specific value of a column.
I have a table like :
+----+------------+------------+---------------+---------------+---------+----------------+---------
| ID | MSISDN | MissedCall | SponsoredCall | AdvanceCredit | ACvalue | SuitablePackId | AutoTimeStamp |
+----+------------+------------+---------------+---------------+---------+----------------+---------------------+
| 1 | 9944994488 | 1 | 0 | 1 | 0 | 1 | 2014-09-18 10:42:55 |
| 4 | 9879877897 | 0 | 1 | 0 | 0 | 2 | 2014-09-18 10:42:55 |
+----+------------+------------+---------------+---------------+---------+----------------+---------------------+
What i need is when i select a row based upon MSISDN , it should return all column names for that row whose value is fix (say 1).
So in above table for MSISDN = 9944994488 it should return
MissedCall
AdvanceCredit
SuitablePackId
What i have tried is :
SELECT COLUMN_NAME as names
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'bi'
AND TABLE_NAME = 'useranalysisresult'
This returns me column names of table.
But how to get column names with specific value.
Thanks for help in advance.
This is too long for a comment.
A SQL query returns a fixed set of columns. You cannot change the set depending on the row. You could do what you want using a prepared statement, although that would seem like an arcane approach.
You could return a single column with values concatenated together. Something like:
select concat_ws(',',
(case when MissedCall = 1 then 'Missed Call' end),
(case when SponsoredCall = 1 then 'Sponsored Call' end),
. . .
)
from useranalysisresult;
This would produce a list in a single column of the flags being set.
Try the below one. Here replace the YOUR_SCHEMA with your actual schema name and YOUR_TABLENAME with your actual table name:
select column_name from information_schema.columns
where YOUR_SCHEMA = //any condition
and table_name='YOUR_TABLENAME';

How to select both sum value of all rows and values in some specific rows?

I have a record table and its comment table, like:
| commentId | relatedRecordId | isRead |
|-----------+-----------------+--------|
| 1 | 1 | TRUE |
| 2 | 1 | FALSE |
| 3 | 1 | FALSE |
Now I want to select newCommentCount and allCommentCount as a server response to the browser. Is there any way to select these two fields in one SQL?
I've tried this:
SELECT `isRead`, count(*) AS cnt FROM comment WHERE relatedRecordId=1 GROUP BY `isRead`
| isRead | cnt |
| FALSE | 2 |
| TRUE | 1 |
But, I have to use a special data structure to map it and sum the cnt fields in two rows to get allCommentCount by using an upper-layer programming language. I want to know if I could get the following format of data by SQL only and in one step:
| newCommentCount | allCommentCount |
|-----------------+-----------------|
| 2 | 3 |
I don't even know how to describe the question. So I got no any search result in Google and Stackoverflow. (Because of My poor English, maybe)
Use conditional aggregation:
SELECT SUM(NOT isRead) AS newCommentCount, COUNT(*) AS allCommentCount
FROM comment
WHERE relatedRecordId = 1;
if I under stand you want show sum of newComments Count and all comments so you can do it like
SELECT SUM ( CASE WHEN isRead=false THEN 1 ELSE 0 END ) AS newComment,
Count(*) AS AllComments From comments where relatedRecord=1
also you can make store procedure for it.
To place two result sets horizontally, you can as simple as use a subquery for an expression in the SELECT CLAUSE as long as the number of rows from the result sets match:
select (select count(*) from c_table where isread=false and relatedRecordId=1 ) as newCommentCount,
count(*) as allCommentCount
from c_table where relatedRecordId=1;

How do i show the name of a column as a row data using a sql query?

I am quite inexperienced with the query writing.
I have a table like this,
+----+--------+------------+------------+------------+
| id | name | Character1 | Character2 | Character3 |
+----+--------+------------+------------+------------+
| 1 | A | 1 | 0 | 0 |
+----+--------+------------+------------+------------+
| 2 | B | 0 | 1 | 0 |
+----+--------+---------------+---------+------------+
i want to make a query where the result would show me like this, where i put a condition to search a name,
+----+--------+---------------+
| id | name | Character |
+----+--------+---------------+
| 1 | A | Character 1 |
+----+--------+---------------+
What will be the query for this?
There you go
select id, name, case 1
WHEN characters1 = 1 THEN characters1
WHEN characters2 = 1 THEN characters2
WHEN YourColumn = 1 THEN YourColumn //if you have more
Else 'no 1' END
from YourTableName where name LIKE '%searhname%'
Replace YourTableName above as your real table name, meanwhile searchname is what you or user is going to type in and search
YourColumn will be character2 and 3... or many more :)
For more information about LIKE, such as the difference between '%name' and 'name%', you may view this link here
You need a CASE expression:
select id, name,
case 1
when Character1 then 'Character1'
when Character2 then 'Character2'
when Character3 then 'Character3'
end Character
from tablename

select Column names having a fixed value for any particular row

I am trying to make a query in mysql to get any column which has a particular value for one specific row.
In Mysql we can get rows based upon any specific value of a column.
I have a table like :
+----+------------+------------+---------------+---------------+---------+----------------+---------
| ID | MSISDN | MissedCall | SponsoredCall | AdvanceCredit | ACvalue | SuitablePackId | AutoTimeStamp |
+----+------------+------------+---------------+---------------+---------+----------------+---------------------+
| 1 | 9944994488 | 1 | 0 | 1 | 0 | 1 | 2014-09-18 10:42:55 |
| 4 | 9879877897 | 0 | 1 | 0 | 0 | 2 | 2014-09-18 10:42:55 |
+----+------------+------------+---------------+---------------+---------+----------------+---------------------+
What i need is when i select a row based upon MSISDN , it should return all column names for that row whose value is fix (say 1).
So in above table for MSISDN = 9944994488 it should return
MissedCall
AdvanceCredit
SuitablePackId
What i have tried is :
SELECT COLUMN_NAME as names
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'bi'
AND TABLE_NAME = 'useranalysisresult'
This returns me column names of table.
But how to get column names with specific value.
Thanks for help in advance.
This is too long for a comment.
A SQL query returns a fixed set of columns. You cannot change the set depending on the row. You could do what you want using a prepared statement, although that would seem like an arcane approach.
You could return a single column with values concatenated together. Something like:
select concat_ws(',',
(case when MissedCall = 1 then 'Missed Call' end),
(case when SponsoredCall = 1 then 'Sponsored Call' end),
. . .
)
from useranalysisresult;
This would produce a list in a single column of the flags being set.
Try the below one. Here replace the YOUR_SCHEMA with your actual schema name and YOUR_TABLENAME with your actual table name:
select column_name from information_schema.columns
where YOUR_SCHEMA = //any condition
and table_name='YOUR_TABLENAME';

MySQL query with conditional statement?

I have a MySQL query left joining two tables. This is the current query result:
id | login | privacy-weight | requires
--------------------------------------------
0 | user | 1 | NULL
0 | user2 | 1 | NULL
0 | user3 | 1 | privacy-weight
The query itself is not important, as I'd only like to add a WHERE condition to the query as it is now.
I need to fetch only values which (in my own words):
IF (`requires` = 'privacy-weight'), then `privacy-weight` must equal = 0;
That means, I need this condition:
WHERE `privacy-weight` = 0
BUT only if this is true:
requires = 'privacy-weight'
Can this be done?
EDIT
Obviously this is too difficult to understand, therefore, an example output:
privacy-weight | requires
-------------------------
0 | NULL
1 | NULL
0 | privacy-weight
1 | NULL
These would be ignored (not fetched):
privacy-weight | requires
-------------------------
1 | privacy-weight
You could use this simple test:
WHERE (requires = 'privacy-weight' AND privacy-weight = 0) OR requires <> 'privacy-weight' OR requires IS NULL
The first part (requires = 'privacy-weight' AND privacy-weight = 0) prevents the output of:
privacy-weight | requires
-------------------------
1 | privacy-weight
But keeps:
privacy-weight | requires
-------------------------
0 | privacy-weight
While the second part OR requires <> 'privacy-weight' OR requires IS NULL will keep the following ones:
privacy-weight | requires
-------------------------
0 | NULL
1 | NULL
1 | NULL
I think this should work:
SELECT id, login, ( IF(requires='privacy-weight',0,privacy-weight) ) AS privacy-weight, requires
FROM [mytable]
WHERE [mywhereclause]
For more information on how the IF function works in MySQL see the docs at http://dev.mysql.com/doc/refman/5.5/en/if.html
WHERE CASE WHEN requires = 'privacy-weight' THEN 0 ELSE privacy-weight END = 0
simply:
WHERE NOT (requires='privacy-weight' AND privacy-weight<>0)
There is an IF() function in mysql as #philwinkle posted but it changes the values of the columns, it doesn't affect the rows. You want to add this to your WHERE statement.
SELECT id, login, `privacy-weight`, requires FROM yourtable
WHERE `privacy-weight`=0 AND requires='privacy-weight'
Edit I've changed this back to answer the OP's question as written.
You can do if condition in where clause
SELECT *
FROM mytable
WHERE IF(requires = 'privacy-weight',privacy-weight = 0,1);
But you can achieve it without if too as you have mentioned you ONLY need
SELECT *
FROM mytable
WHERE requires = 'privacy-weight'
AND privacy - weight = 0;