I have a tabular form in which I need to generate a dynamic amount of select lists based on the number of values in COL1 that are relevant to the query.
APEX_ITEM.SELECT_LIST_FROM_QUERY_XL(5, COL1, 'query...',p_show_null=>'NO') "COL1"
This works fine when the query returns at least one row. It creates x amount of select lists where x is the number of rows returned by the query. However, when no rows are returned, no select lists are created. How can I make it generate one select list when the query returns no results?
You could do something like this:
select ...,
APEX_ITEM.SELECT_LIST_FROM_QUERY_XL(5, COL1, 'query...',p_show_null=>'NO') "COL1"
from ...
where ...
union all
select ...,
APEX_ITEM.SELECT_LIST_FROM_QUERY_XL(5, 'xxx', 'query...',p_show_null=>'NO') "COL1"
from dual
where not exists (select null from <first query>)
Related
I have this huge table upon which I apply a lot of processing (using CTEs), and I want to perform a UNION ALL on 2 particular CTEs.
SELECT *
, 0 AS orders
, 0 AS revenue
, 0 AS units
FROM secondary_prep_cte WHERE purchase_event_flag IS FALSE
UNION ALL
SELECT *
FROM results_orders_and_revenues_cte
I get a "Column 1164 in UNION ALL has incompatible types : STRING,DATE at [97:5]
Obviously I don't know the name of the column, and I'd like to debug this but I feel like I'm going to waste a lot of time if I can't pin-point which column is 1164.
I also think this is a problem of the order of columns between the CTEs, so I have 2 questions:
How do I identify the 1164th column
How do I order my columns before performing the UNION ALL
I found this similar question but it is for MSSQL, I am using BigQuery
You can get information from INFORMATION_SCHEMA.COLUMNS but you'll need to create a table or view from the CTE:
CREATE OR REPLACE VIEW `project.dataset.secondary_prep_view` as select * from (select 1 as id, "a" as name, "b" as value)
Then:
SELECT * FROM dataset.INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'secondary_prep_view';
I want to write a big query to fetch the value in a column from multiple tables in a given dataset. But the column name in each table is different like colA, colB, colC and so on. How to accomplish this?
I have many tables in my dataset where one of the column contains web URL. However this column name is different in each table. I want to process all the URL's of all the tables.
I checked in this link How to combine multiple tables that vary slightly in columns. However it talks about limited number of column name variation and limited number of tables.
I know
SELECT
column_name
FROM
`bq-project.bq-dataset.INFORMATION_SCHEMA.COLUMNS`
group by 1
will give distinct column, but not sure how to proceed
You may create a view to translate column names.
CREATE VIEW my_dataset.aggregated_tables AS
SELECT * EXCEPT (colA), colA as url FROM table_a
UNION
SELECT * EXCEPT (colB), colB as url FROM table_b
UNION
SELECT * EXCEPT (colC), colC as url FROM table_c;
For fun, discovering what column has an URL, using JS UDFs:
CREATE TEMP FUNCTION urls(x STRING)
RETURNS STRING
LANGUAGE js AS r"""
function isURL(str) {
// https://stackoverflow.com/a/49185442/132438
return /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(str);
}
obj = JSON.parse(x);
for (var key in obj){
if(isURL(obj[key])) return(obj[key]);
}
""";
WITH table_a AS (SELECT 'https://google.com/' aa)
,table_b AS (SELECT 'http://medium.com/#hoffa' ba, 'noturl' bb)
,table_c AS (SELECT 'bigquery' ca, 'noturl' cb, 'https://twitter.com/felipehoffa' cc)
SELECT urls(x) url
FROM (
SELECT TO_JSON_STRING(t) x FROM table_a t
UNION ALL
SELECT TO_JSON_STRING(t) FROM table_b t
UNION ALL
SELECT TO_JSON_STRING(t) FROM table_c t
)
We have a table that has claim number, amount, and code for writeoffs. We do multiple writeoffs per record so we have 4 separate instances labeled as:
WOCLAIMNO1,WOAMT1,WOCODE1
WOCLAIMNO2,WOAMT2,WOCODE2
WOCLAIMNO3,WOAMT3,WOCODE3
WOCLAIMNO4,WOAMT4,WOCODE4
Currently we need to run 4 separate queries and then just copy and paste them all into one spreadsheet. We need to get the results of every record that has the WO code including the word 'Warehouse'.
So if you take the example table below and run query with that criteria you should get the output expected. What I need is a way to run just one query on all the columns instead of running each query separately, meaning query WO1, then WO2, then WO3, and then WO4 and then combining all the results together manually.
Sample Table
Output
You could just use UNION ALL :
SELECT
WOCLAIMNO1 AS WOCLAIMNO,
WOAMT1 AS WOAMT,
WOCODE1 AS WOCODE
FROM
mytable
WHERE
WOCODE1 LIKE '%Warehouse%'
UNION ALL
SELECT WOCLAIMNO2, WOAMT2, WOCODE2 FROM mytable WHERE WOCODE2 LIKE '%Warehouse%'
UNION ALL
SELECT WOCLAIMNO3, WOAMT3, WOCODE3 FROM mytable WHERE WOCODE3 LIKE '%Warehouse%'
UNION ALL
SELECT WOCLAIMNO4, WOAMT4, WOCODE4 FROM mytable WHERE WOCODE4 LIKE '%Warehouse%'
I saw the following posted on a basic way to de-dup entries, without explanation of how it works. I see that it works, but I want to know the workings of how it works and the process in which it evaluates. Below I will post the code, and my thoughts. I am hoping that somebody can tell me if my thought process on how this is evaluated step by step is correct, or if I am off, can somebody please break it down for me.
CREATE TABLE #DuplicateRcordTable (Col1 INT, Col2 INT)
INSERT INTO #DuplicateRcordTable
SELECT 1, 1
UNION ALL
SELECT 1, 1
UNION ALL
SELECT 1, 1
UNION ALL
SELECT 1, 2
UNION ALL
SELECT 1, 2
UNION ALL
SELECT 1, 3
UNION ALL
SELECT 1, 4
GO
This returns a basic table:
Then this code is used to exclude duplicates:
SELECT col1,col2
FROM #DuplicateRcordTable
EXCEPT
SELECT col1,col2
FROM #DuplicateRcordTable WHERE 1=0
My understanding is that where 1=0 creates a "temp" table structured the same but has no data.
Does this code then start adding data to the new empty table?
For example does it look at the first Col1, Col2 pair of 1,1 and say "I don't see it in the table" so it adds it to the "temp" table and end result, then checks the next row which is also 1,1 and then sees it already in the "temp" table so its not added to the end result....and so on through the data.
EXCEPT is a set operation that removes duplicates. That is, it takes everything in the first table that is not in the second and then does duplicate removal.
With an empty second set, all that is left is the duplicate removal.
Hence,
SELECT col1, col2
FROM #DuplicateRcordTable
EXCEPT
SELECT col1, col2
FROM #DuplicateRcordTable
WHERE 1 = 0;
is equivalent to:
SELECT DISTINCT col1, col2
FROM #DuplicateRcordTable
This would be the more typical way to write the query.
This would also be equivalent to:
SELECT col1,col2
FROM #DuplicateRcordTable
UNION
SELECT col1,col2
FROM #DuplicateRcordTable
WHERE 1 = 0;
The reason that this works is due to the definition of EXCEPT which according to the MS docs is
EXCEPT returns distinct rows from the left input query that aren't
output by the right input query.
The key word here being distinct. Putting where 1 = 0 makes the second query return no results, but the EXCEPT operator itself then reduces the rows from the left query down to those which are distinct.
As #Gordon Linoff says in his answer, there is a simpler, more straightforward way to accomplish this.
The fact that the example uses the same table in the left and right queries could be misleading, the following query will accomplish the same thing, so long as the values in the right query don't exist in the left:
SELECT col1, col2
FROM #DuplicateRecordTable
EXCEPT
SELECT -1, -1
REF: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/set-operators-except-and-intersect-transact-sql?view=sql-server-2017
I have two sql server tables with the same structure. In a stored procedure I have a Select from the first table. Occasionally I want to select from the second table as well based on a passed in parameter.
I would like a way to do this without resorting to using dynamic sql or temporary tables.
Pass in param = 1 to union, anything else to only return the first result set:
select field1, field2, ... from table1 where cond
union
select field1, field2, ... from table2 where cond AND param = 1
If they are both the exact same structure, then why not have a single table with a parameter that differentiates the two tables? At that point, it becomes a simple matter of a case statement on the parameter on which results set you receive back.
A second alternative is dual result sets. You can select multiple result sets out of a stored procedure. Then in code, you would either use DataReader.NextResult or DataSet.Tables(1) to get at the second set of data. It will then be your code's responsibility to place them into the same collection or merge the two tables.
A THIRD possibility is to utilize an IF Statement. Say, pass in an integer with the expected possible values of 1,2, 3 and then have something along this in your actual stored procedure code
if #Param = 1 Then
Select From Table1
if #Param = 2 THEN
Select From Table2
if #Param = 3 Then
Select From Table1 Union Select From Table 2
A fourth possibility would be to have two distinct procedures one which runs a union and one which doesn't and then make it your code's responsibility to determine which one to call based on that parameter, something like:
myCommandObject.CommandText = IIf(myParamVariable = true, "StoredProc1", StoredProc2")
It's pretty easy.
/* Always return tableX */
select colA, colB
from tableX
union
select colA, colB
from tableY
where #parameter = 'IncludeTableY' /* Will union with an empty set otherwise */
If this isn't immediately apparent (it often isn't), consider the examples below. The primary thing to remember is that the if the where clause evaluates to true for a row, it is returned otherwise it's discarded.
This always evaluates to true so every row is returned.
select *
from tableX
where 1 = 1
This always evaluates to false so no rows are returned (sometimes used as a quick and dirty get-me-the-columns query).
select *
from tableX
where 1 = 0
this will return values from either table, depending on if you passed a value on the parameter
select field1, field2, ... from table1 where #p1 is null
union
select field1, field2, ... from table2 where #p1 is not null
you just need to add the rest of your criteria for the where clause
Use a view.
CREATE view_both
AS
SELECT *, 1 AS source
FROM table1
UNION ALL
SELECT *, 2 AS source
FROM table2
SELECT * FROM view_both WHERE source < #source_flag
The optimizer determines which, or both, tables to use based on source without requiring it to be indexed.