Combining Columns from different tables - sql

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;

Related

Stacking my conditions in a CASE statement it's not returning all cases for each member

SELECT DISTINCT
Member_ID,
CASE
WHEN a.ASTHMA_MBR = 1 THEN 'ASTHMA'
WHEN a.COPD_MBR = 1 THEN 'COPD'
WHEN a.HYPERTENSION_MBR = 1 THEN 'HYPERTENSION'
END AS DX_FLAG
So a member may have more than one, but my statement is only returning one of them.
I'm using Teradata and trying to convert multiple columns of boolean data into one column. The statement is only returning one condition when members may have 2 or more. I tried using Select instead of Select Distinct and it made no difference.
This is a kind of UNPIVOT:
with base_data as
( -- select the columns you want to unpivot
select
member_id
,date_col
-- the aliases will be the final column value
,ASTHMA_MBR AS ASTHMA
,COPD_MBR AS COPD
,HYPERTENSION_MBR AS HYPERTENSION
from your_table
)
,unpvt as
(
select member_id, date_col, x, DX_FLAG
from base_data
-- now unpivot those columns into rows
UNPIVOT(x FOR DX_FLAG IN (ASTHMA, COPD, HYPERTENSION)
) dt
)
select member_id, DX_FLAG, date_col
from unpvt
-- only show rows where the condition is true
where x = 1

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';

ORACLE SQL Pivot Issue

I am trying to pivot a sql result. I need to do this all in the one query. The below is telling me invalid identifier for header_id. I am using an Oracle database.
Code
Select * From (
select ppd.group_id,g.group_name, ct.type_desc,ht.hos_cat_descr
from item_history ih, item ci, contract ppd,
header ch, group g, cd_std_type ct, cd_hos h,
cd_std_hospital_cat ht
where ih.item_id = ci.item_id
and ih.header_id = ch.header_id
and ci.hos_id = h.hos_id
and ih.item_id = ci.item_id
and ch.user_no = ppd.user_no
and ppd.group_id = g.group_id
and ch.header_type = ct.header_type_id
and ci.hos_id = h.hos_id
and h.cat_id = ht.cat_id
)
Pivot
(
count(distinct header_id) as Volume
For hos_cat_descr IN ('A')
)
Your inner query doesn't have header_id in its projection, so the pivot clause doesn't have that column available to use. You need to add it, either as:
Select * From (
select ppd.group_id,g.group_name, ct.type_desc,ht.hos_cat_descr,ih.header_id
---------------------------------------------------------------^^^^^^^^^^^^^
from ...
)
Pivot
(
count(distinct header_id) as Volume
For hos_cat_descr IN ('A')
)
or:
Select * From (
select ppd.group_id,g.group_name, ct.type_desc,ht.hos_cat_descr,ch.header_id
---------------------------------------------------------------^^^^^^^^^^^^^
from ...
)
Pivot
(
count(distinct header_id) as Volume
For hos_cat_descr IN ('A')
)
It doesn't really matter which, since those two values must be equal as they are part of a join condition.
You could achieve the same thing with simpler aggregation instead of a pivot, but presumably you are doing more work in the pivot really.

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

Adding argument to SELECT statement with UNION changes record number

When I add a new argument to the SELECT clause of a UNION, I get more records... how can this be? Isn't a UNION just mashing them together? Example:
EDIT: They're absolutely distinct. the code column is either "IN" or "OUT", and that's what I'm using to separate the two.
EDIT2: UNION ALL gives me 80 records, like it should, but it's odd because my two SELECT statements are absolutely distinct.
FINAL EDIT: Ultimate problem was records within one of my SELECT statements being not DISTINCT, not between the two SELECT statements. Thanks all.
-- Yields 76 records
SELECT
f.date
, f.code
, f.cost
FROM a.fact f
WHERE f.code = 'IN'
UNION
SELECT
f2.date
, f2.code
, f2.cost
FROM a.fact2 f2
WHERE f2.code = 'OUT'
;
-- Yields 80 records
SELECT
f.key
, f.date
, f.code
, f.cost
FROM a.fact f
WHERE f.code = 'IN'
UNION
SELECT
f2.key
, f2.date
, f2.code
, f2.cost
FROM a.fact2 f2
WHERE f2.code = 'OUT'
;
change UNION to UNION ALL and you should get the same results. UNION selects distinct rows, UNION ALL should select all.
By default UNION selects distinct results, there must be duplicates between your result sets.
The union all will solve your problem, as mentioned in a previous answer, it selects the distinct values only
References Oracle docs.