SQL Server 2008
I have a table MyTable with columns A, B, C, D
When I select a row I want a list of only those columns with non-null/blanks. The result set would be
A
C
D
if B was null in my row.
Actually, there may be a column E someday. But I can get all possible column names from another table and need to check if MyTable has any of them and if so which ones have data for the row I selected
Thus:
select * from MyTable where ID = 6
select ColumnName from AllColumnNames
For each ColumnName in the result
if ColumnName exists in MyTable AND there is data in it where ID = 6, add ColumnName to output.
There's gotta be a way to do this in one query?
This will convert your table to XML in the CTE and then it uses XQuery to find the node names that does not have empty values. This will work if your column names does not break the rules for XML node names.
;with C(TableXML) as
(
select *
from MyTable
where ID = 6
for xml path('T'), elements xsinil, type
)
select T.X.value('local-name(.)', 'sysname') as ColumnName
from C
cross apply C.TableXML.nodes('/T/*') as T(X)
where T.X.value('.', 'nvarchar(max)') <> ''
Try here: https://data.stackexchange.com/stackoverflow/query/59187
Add this the the where clause if you want to exclude the ID column as well.
T.X.value('local-name(.)', 'sysname') <> 'ID'
Related
Is there any possible way I can find and set the column name by giving alias
for example
I have a sql queries which contain 4 column name fields. 3 fields are common in all the queries
id, name, field
and there is another field which column name get change every time but the only common thing in that field it has a postfix as __type
so my sql query looks like this
SELECT * from table_name
id, name, field, system_data__value
is there any possible way I can add alias to the name where I found __type as type
so if I run my queries then it look like this
SELECT * from table_name
id, name, field, type
You may use UNION ALL for to set the aliases to the columns posessionally.
You must know some value which cannot present in some column (id = -1 in shown code) for fake row removing.
SELECT *
FROM (
SELECT -1 id, NULL name, NULL field, NULL alias_for_column_4
UNION ALL
SELECT * from table_name -- returns id, name, field, system_data__value
) subquery
WHERE id > 0 -- removes fake row
It is possible that the values in fake subquery needs in explicit CAST() calls for correct datatype of the output columns setting.
What I mean is, I have table with a "list" column. The data that goes into the "list" is related to addresses, so I sometimes get repeated zip codes for one record in that field.
For example, "12345,12345,12345,12456".
I want to know if it's possible to construct a query that would find the records that have an unknown string that duplicates within the field, such that I would get the records like "12345,12345,12345,12456", but not ones like "12345,45678,09876".
I hope that makes sense.
Yes, it is possible. You need to use a numbers table to convert your delimited string into rows, then use group by to find duplicates, e.g.
CREATE TABLE T (ID INT, List VARCHAR(100));
INSERT INTO T (ID, List)
VALUES (1, '12345,12345,12345,12456'), (2, '12345,45678,09876');
SELECT
T.ID,
SUBSTRING_INDEX(SUBSTRING_INDEX(T.list, ',', n.Number), ',', -1) AS ListItem
FROM T
INNER JOIN
( SELECT 1 AS Number UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5
) AS n
ON CHAR_LENGTH(T.list)-CHAR_LENGTH(REPLACE(T.list, ',', ''))>=n.Number-1
GROUP BY T.ID, ListItem
HAVING COUNT(*) > 1;
If you don't have a numbers table you can create one in a derived query as I have above with UNION ALL
Example on DB Fiddle
With that being said, this is almost certainly not the right way to store your data, you should instead use a child table, e.g.
CREATE TABLE ListItems
(
MainTableId INT NOT NULL, --Foreign Key to your current table
ItemName VARCHAR(10) NOT NULL -- Or whatever data type you need
);
Then your query is much more simple:
SELECT T.ID, li.ItemName
FROM T
INNER JOIN ListItems AS li
ON li.MainTableId = T.ID
GROUP BY T.ID, li.ItemName
HAVING COUNT(*) > 1;
If you need to recreate your original format, this is easily done with GROUP_CONCAT():
SELECT T.ID,
GROUP_CONCAT(li.ItemName) AS List
FROM T
INNER JOIN ListItems AS li
ON li.MainTableId = T.ID
GROUP BY T.ID;
Example on DB Fiddle
I am still unclear what your desired result is based on your question however if it is simply to get all rows where there is a duplicate entry in column list you could do the following:
SELECT * FROM TABLE
WHERE COLUMN IN
(SELECT COLUMN FROM TABLE
having count(*) >1)
I have an array ('abc','def','ghi','jkl'). I want to find the values which are not in mysql table.
That is, if 'def'is not in the table, then it should show 'def' and so on.
My query was:
SELECT column FROM table WHERE column not in ('abc','def','ghi','jkl')
But its wrong. How can I get the values which are not there in the column?
You should put these values first in some table and then do "Not in" like :
SELECT column FROM table WHERE column not in (select distinct col1 from table1).
Here is how you can do it:
select x.col
from (values row('def'),row('abc'),row('ghi')) x(col)
left join table t on t.col = x.col
Where t.col is null
Say, I have a table
A B C D E F
1 2 4 3 6 5
4 2 3 1 6 5
4 5 3 6 1 2
How can one get an output based on rearranging based on its data. For example,
ABDCFE
DBCAFE
EFCABD
is it possible?
EDIT:
The question seems to be asking: How can I get the list of column names in order by value?
I got it. You want to sort the values in each row and show the names of the columns in order.
Let me assume that you have a row id, so you can identify each row. Then:
select id, group_concat(which order by val) as ordered_column_names
from ((select id, a as val, 'A' as which from t) union all
(select id, b, 'B' as which from t) union all
(select id, c, 'C' as which from t) union all
(select id, d, 'D' as which from t) union all
(select id, e, 'E' as which from t) union all
(select id, f, 'F' as which from t)
) t
group by id
order by id;
SQL is fundamentally not the tool to do the operation you describe, because it violates the concept of a relation. I don't mean the common use of "relation" meaning a relationship, I mean the mathematical definition of relation.
There is no order of columns in a relation. The columns are a set, which is by definition unordered. Columns are identified by their name, not their position left-to-right.
All the entries in rows under each respective named column must be part of the same data domain. If you mix them around on a row-by-row basis, you're violating this.
I guess all your columns A through F are actually using values in the same data domain, or else reordering them wouldn't make any sense. If this is true, then you're violating First Normal Form by defining a table with repeating groups of columns. You should instead have all six columns be in one column of a second table. Then it becomes very easy to sort them by value.
Basically, what you're trying to do is better solved by formatting the data results in some application code.
There is a way to do it ,get coulmn name by column ordinal order and print it.
For each value in coulmn iterate this and get the column name for the ordinal specified in cloumn data. Here ordinal position is value in each coulmn data. Iterate for each row and each column and your problem is solved.
select column_name
from information_schema.columns
where table_name = 'my_table_name' and ordinal_position = 2;
It appears that you are asking for output where each row in the output is just a specification of the order of the data values in the columns.
Then, if the values are always integers between 1 and 5, you can do it by outputting a character value of 'A' where the data value is 1, a 'B' where the data value is 2, etc. This SQL will do that.
Select Char(A+64)A, Char(B+64) B,
Char(C+64) C, Char(D+64) D,
Char(E+64) E, Char(F+64) F
From table
if the want the column sort order in one output column, you could also do this:
Select Char(A+64) + Char(B+64) +
Char(C+64) + Char(D+64) +
Char(E+64) + Char(F+64) SortOrder
From table
I obtain a series of values that appear only one time in my database using COUNT in mysql that list below:
valueName
---------
value1
value2
value3
value4
I need a script that retrieves all records in a table where valueName are not the values listed in the initial count, and I need this two steps to run in a single script (doesn't matter how many parts it has).
I've got the script to obtain the list above like this:
SELECT field AS new_name FROM table GROUP BY field HAVING COUNT(field) = 1;
And it works.
The problem is that I don't know how to work with the aggregated result of the first step. Maybe using some kind of function. Or loop (I don't think in SQL..).
I've tried different things like attaching a COUNT inside a WHERE clause and others but it doesn't work.
Please help!
Use a join:
select t.*
from table t join
(SELECT field
FROM table
GROUP BY field
HAVING COUNT(field) > 1
) filter
on t.field = filter.field;
If you have a primary key in your table and an index on table(field, pk), the following is probably faster:
select t.*
from table t
where exists (select 1
from table t2
where t2.field = t.field and t2.pk <> t.pk
);
Try this:
SELECT table.* FROM table
JOIN
(SELECT field FROM table GROUP BY field HAVING COUNT(field) > 1) newtable
ON
table.field = newtable.field;
This should work.