UNION several WITH results - sql

I have two similar queryes.
Like folowing:
with CategoryHistory AS (
SELECT
category.GUID as id,
----HERE MANY FIELDS----
category.__$operation AS operation,
map.tran_begin_time as beginT,
map.tran_end_time as endT
FROM cdc.fn_cdc_get_all_changes_dbo_EXT_BalanceHC_ZapasCategory(sys.fn_cdc_get_min_lsn('dbo_EXT_BalanceHC_ZapasCategory'), sys.fn_cdc_get_max_lsn(), 'all') AS category
INNER JOIN [cdc].[lsn_time_mapping] map
ON category.[__$start_lsn] = map.start_lsn
)
SELECT operation, fields, valueses, beginT, endT FROM CategoryHistory
unpivot ( [valueses] for fields in
(
----HERE MANY FIELDS----
))p
Can i UNION of WITH results? Problem that i want UNPIVOT some fields from result of query.

Perhaps you simply want something like this:
SELECT ch.operation, ch.beginT, ch.endT, v.field, v.val
FROM CategoryHistory ch cross apply
(values ('field1', field1), ('field2', field2), . . .
) f(field, val);
I find this easier than using unpivot.

Related

SQL - expand dataset into lookup table?

I currently have a legacy table that looks like the one below.
This is a set of rules that our business has stored over the years. the issue is the "all" and "both" values really should be separated out into rows so they can be queried more efficiently.
For example, the contract length column can only ever be between 1 and 5, the type column can only ever be "gas" or "water" and the sales channel "internal" or "external". Instead of saying all or both, another row should exist with the specific rule and the table should look like the below.
So this will have a row for every variation in the first table.
I didn't think it would be a long task to manually do myself. but I was wrong :)
Does anyone have any idea on how to achieve this quickly in SQL? I would say what I have tried so far...but I am completely stumped on this one so am wondering if it can even be done at all?
This could be done in a single sql statement, but for the sake of your mental health and the ability to check interim result sets before you get to the final output is probably a lot healthier and less risky.
I would approach this with a UNION query, one set of UNIONs for each column that should be split out to more granular rows.
For instance for contractlength:
SELECT Supplier, 1, Type, SalesChannel FROM yourtable WHERE contractLength in ('1', 'All')
UNION ALL
SELECT Supplier, 2, Type, SalesChannel FROM yourtable WHERE contractLength in ('2', 'All')
UNION ALL
SELECT Supplier, 3, Type, SalesChannel FROM yourtable WHERE contractLength in ('3', 'All')
UNION ALL
SELECT Supplier, 4, Type, SalesChannel FROM yourtable WHERE contractLength in ('4', 'All')
UNION ALL
SELECT Supplier, 5, Type, SalesChannel FROM yourtable WHERE contractLength in ('5', 'All')
You can write those results out to a temp table, and then build your query for type on top of it writing to a new temp table.
SELECT Supplier, contractLength, 'Gas', SalesChannel FROM previousTempTable WHERE type in ('Gas','Both')
UNION ALL
SELECT Supplier, contractLength, 'Water', SalesChannel FROM previousTempTable WHERE type in ('Gas','Both')
Rinse and repeat for SalesChannel.
There's other more elegant ways to solve this with some SELECT DISTINCT and cross joins, but your list of values for each column is limited and this solution I'm proposing feels like a quick easy way to get your data in shape. It's also easy to understand if this is auditable data or the process needs to be repeated.
You don't need to query your table multiple times, or use temp tables. You can do this pretty elegantly with conditional unpivots, by using CROSS APPLY
SELECT
t.Supplier,
c1.ContractLength,
c2.Type,
c3.SalesChannel
FROM YourTable t
CROSS APPLY (
SELECT t.ContractLength
WHERE t.ContractLength <> 'All'
UNION ALL
SELECT *
FROM (VALUES
(1),(2),(3),(4),(5)
) v(ContractLength)
WHERE t.ContractLength = 'All'
) c1
CROSS APPLY (
SELECT t.Type
WHERE t.Type <> 'Both'
UNION ALL
SELECT *
FROM (VALUES
('Gas'),('Water')
) v(Type)
WHERE t.Type = 'Both'
) c2
CROSS APPLY (
SELECT t.SalesChannel
WHERE t.SalesChannel <> 'Both'
UNION ALL
SELECT *
FROM (VALUES
('Internal'),('External')
) v(SalesChannel)
WHERE t.SalesChannel = 'Both'
) c3;
A somewhat less efficient, but more compact, version of the same, is to use normal joins against the VALUES clauses
SELECT
t.Supplier,
c1.ContractLength,
c2.Type,
c3.SalesChannel
FROM YourTable t
JOIN (VALUES
(1),(2),(3),(4),(5)
) c1(ContractLength)
ON c1.ContractLength = t.ContractLength OR t.ContractLength = 'All'
JOIN (VALUES
('Gas'),('Water')
) c2(Type)
ON c2.Type = t.Type OR t.Type = 'Both'
JOIN (VALUES
('Internal'),('External')
) c3(SalesChannel)
ON c3.SalesChannel = t.SalesChannel OR t.SalesChannel = 'Both';

Display Columns To Rows

I have a table that looks like this:
AccountNumber, Warning01, Warning01ExpirationDate, Warning02, Waring02ExpirtionDate, .....
1234, 3,'2017-09-06',0, null
78976, 1,'2015-04-03',2,null
I would like to show the result as follow:
AccountNumber,Warning,ExpirationDate
1234,2,'2017-09-06'
78976,1,'2015-04-03'
78976,2,null
if the warning is 0 or null, I want to ignore it.
any ideas?
In T-SQL, just use cross apply and values() to unpivot your dataset:
select x.*
from mytable t
cross apply (values
(t.accountNumber, t.warning01, t.warning01expirationDate),
(t.accountNumber, t.warning02, t.warning02expirationDate)
) as x(accountNumber, warning, expirationDate)
where x.warning <> 0

How to transform 1 line with multiple in 2 lines with multiple columns on SQL Server?

I have the following table:
I need to do a query to return the following result:
I tried with UNPIVOT but it doesen't work. I have the 12 months, but for example I put just 2.
How can I do this?
You can use apply :
select t.Sector, tt.*
from table t cross apply
( values ('Jan', Jan_Estimated, Jan_Sold),
('Feb', Feb_Estimated, Feb_Sold),
. . .
) tt (Month, Val_Estimated, Val_Sold);
You could use CROSS APPLY:
SELECT tab.sector, sub.*
FROM tab
CROSS APPLY (VALUES ('Jan', Jan_estimated, Jan_sold),
('Feb', Feb_estimated, Feb_sold)
)sub(Month,Val_estimated, Val_sold)
You could use UNPIVOT:
SELECT sector, [Month] = Substring(col1,1,3), val_Estimated, val_Sold
FROM (
SELECT * FROM [tableName]
) as t
UNPIVOT ( val_Estimated for col1 IN (jan_estimated,feb_estimated)) AS unpvt
UNPIVOT ( val_Sold for col2 in (jan_sold, feb_sold)) up2
WHERE SUBSTRING(col1,1,3) = SUBSTRING(col2,1,3)

Using a case statement as an if statement

I am attempting to create an IF statement in BigQuery. I have built a concept that will work but it does not select the data from a table, I can only get it to display 1 or 0
Example:
SELECT --AS STRUCT
CASE
WHEN (
Select Count(1) FROM ( -- If the records are the same, then return = 0, if the records are not the same then > 1
Select Distinct ESCO, SOURCE, LDCTEXT, STATUS,DDR_DATE, TempF, HeatingDegreeDays, DecaTherms
from `gas-ddr.gas_ddr_outbound.LexingtonDDRsOutbound_onchange_Prior_Filtered`
Except Distinct
Select Distinct ESCO, SOURCE, LDCTEXT, STATUS,DDR_DATE, TempF, HeatingDegreeDays, DecaTherms
from `gas-ddr.gas_ddr_outbound.LexingtonDDRsOutbound_onchange_Latest_Filtered`
)
)= 0
THEN
(Select * from `gas-ddr.gas_ddr_outbound.LexingtonDDRsOutbound_onchange_Latest`) -- This Does not
work Scalar subquery cannot have more than one column unless using SELECT AS
STRUCT to build STRUCT values at [16:4] END
SELECT --AS STRUCT
CASE
WHEN (
Select Count(1) FROM ( -- If the records are the same, then return = 0, if the records are not the same then > 1
Select Distinct ESCO, SOURCE, LDCTEXT, STATUS,DDR_DATE, TempF, HeatingDegreeDays, DecaTherms
from `gas-ddr.gas_ddr_outbound.LexingtonDDRsOutbound_onchange_Prior_Filtered`
Except Distinct
Select Distinct ESCO, SOURCE, LDCTEXT, STATUS,DDR_DATE, TempF, HeatingDegreeDays, DecaTherms
from `gas-ddr.gas_ddr_outbound.LexingtonDDRsOutbound_onchange_Latest_Filtered`
)
)= 0
THEN 1 --- This does work
Else
0
END
How can I Get this query to return results from an existing table?
You question is still a little generic, so my answer same as well - and just mimic your use case at extend I can reverse engineer it from your comments
So, in below code - project.dataset.yourtable mimics your table ; whereas
project.dataset.yourtable_Prior_Filtered and project.dataset.yourtable_Latest_Filtered mimic your respective views
#standardSQL
WITH `project.dataset.yourtable` AS (
SELECT 'aaa' cols, 'prior' filter UNION ALL
SELECT 'bbb' cols, 'latest' filter
), `project.dataset.yourtable_Prior_Filtered` AS (
SELECT cols FROM `project.dataset.yourtable` WHERE filter = 'prior'
), `project.dataset.yourtable_Latest_Filtered` AS (
SELECT cols FROM `project.dataset.yourtable` WHERE filter = 'latest'
), check AS (
SELECT COUNT(1) > 0 changed FROM (
SELECT DISTINCT cols FROM `project.dataset.yourtable_Latest_Filtered`
EXCEPT DISTINCT
SELECT DISTINCT cols FROM `project.dataset.yourtable_Prior_Filtered`
)
)
SELECT t.* FROM `project.dataset.yourtable` t
CROSS JOIN check WHERE check.changed
the result is
Row cols filter
1 aaa prior
2 bbb latest
if you changed your table to
WITH `project.dataset.yourtable` AS (
SELECT 'aaa' cols, 'prior' filter UNION ALL
SELECT 'aaa' cols, 'latest' filter
) ......
the result will be
Row cols filter
Query returned zero records.
I hope this gives you right direction
Added more explanations:
I can be wrong - but per your question - it looks like you have one table project.dataset.yourtable and two views project.dataset.yourtable_Prior_Filtered and project.dataset.yourtable_Latest_Filtered which present state of your table prior and after some event
So, first three CTE in the answer above just mimic those table and views which you described in your question.
They are here so you can see concept and can play with it without any extra work before adjusting this to your real use-case.
For your real use-case you should omit them and use your real table and views names and whatever columns the have.
So the query for you to play with is:
#standardSQL
WITH check AS (
SELECT COUNT(1) > 0 changed FROM (
SELECT DISTINCT cols FROM `project.dataset.yourtable_Latest_Filtered`
EXCEPT DISTINCT
SELECT DISTINCT cols FROM `project.dataset.yourtable_Prior_Filtered`
)
)
SELECT t.* FROM `project.dataset.yourtable` t
CROSS JOIN check WHERE check.changed
It should be a very simple IF statement in any language.
Unfortunately NO! it cannot be done with just simple IF and if you see it fit you can submit a feature request to BigQuery team for whatever you think makes sense

Combining Columns from different tables

I've write a SQL code to combine several columns from different tables.
SELECT *
FROM
(
SELECT PD_BARCODE
FROM docsadm.PD_BARCODE
WHERE SYSTEM_ID = 11660081
) t,
(
SELECT A_JAHRE
FROM docsadm.A_PD_DATENSCHUTZ
WHERE system_ID = 2066
) t2,
(
SELECT PD_PART_NAME
FROM docsadm.PD_FILE_PART
WHERE system_id = 11660082
) t3;
code works fine but if one of my where clause is not found in a table,the result is null even the other columns have value. How you can solve this problem?
It looks like you are doing a cross join between the three subquery tables. This would probably only yield output which makes sense if each subquery return a single value. I might suggest instead that you use a UNION ALL here:
SELECT ISNULL(PD_BARCODE, 'NA' AS value
FROM docsadm.PD_BARCODE WHERE SYSTEM_ID = 11660081
UNION ALL
SELECT ISNULL(A_JAHRE, 'NA')
FROM docsadm.A_PD_DATENSCHUTZ WHERE system_ID = 2066
UNION ALL
SELECT ISULL(PD_PART_NAME, 'NA')
FROM docsadm.PD_FILE_PART WHERE system_id = 11660082
The above union query might require a slight modification if the three columns being select don't all have the same type (which I assume to be varchar in my query).
If you really need these three points of data as separate columns, then you can just include the three subqueries as items in an outer select:
SELECT
(SELECT ISNULL(PD_BARCODE, 'NA')
FROM docsadm.PD_BARCODE WHERE SYSTEM_ID = 11660081) AS PD_BARCODE,
(SELECT ISNULL(A_JAHRE, 'NA')
FROM docsadm.A_PD_DATENSCHUTZ WHERE system_ID = 2066) AS A_JAHRE,
(SELECT ISNULL(PD_PART_NAME, 'NA')
FROM docsadm.PD_FILE_PART WHERE system_id = 11660082) AS PD_PART_NAME;
Note that as the above is written we simply including the subqueries as values in the select statement. But as you wrote your original query, you are joining the subqueries as separate tables.
Here is Query.
You can replace the word 'empty' by your required word or value
SELECT isnull(
(
SELECT PD_BARCODE
FROM docsadm.PD_BARCODE
WHERE SYSTEM_ID = 11660081
), 'Empty') AS PD_BARCODE,
isnull(
(
SELECT A_JAHRE
FROM docsadm.A_PD_DATENSCHUTZ
WHERE system_ID = 2066
), 'Empty') AS A_JAHRE,
isnull(
(
SELECT PD_PART_NAME
FROM docsadm.PD_FILE_PART
WHERE system_id = 11660082
), 'Empty') AS PD_PART_NAME;
This is a special case since you would be getting only one value per query of yours which you are trying to put up as column. In this case, you can use SQL PIVOT clause with UNION ALL of your queries like shown below. MIN can be used for aggregation in this case.
This would mean, you can get your data row-wise as you like, even for multiple different fields and then pivot it into columns in one go.
SELECT * FROM
(
SELECT 'PD_BARCODE' as KeyItem, PD_BARCODE Name from docsadm.PD_BARCODE
where SYSTEM_ID=11660081
UNION ALL
SELECT 'A_JAHRE', A_JAHRE from docsadm.A_PD_DATENSCHUTZ
where system_ID=2066
UNION ALL
select 'PD_PART_NAME', PD_PART_NAME from docsadm.PD_FILE_PART
where system_id=11660082
) VTABLE
PIVOT(MIN(Name)
FOR KeyItem IN ([PD_BARCODE], [A_JAHRE], [PD_PART_NAME])) as pivotData;