How to make the number of columns same using 'Union' in postgresql? - postgresql

Here is the code:
SELECT 0 customer_id, 0 store_id, '' first_name, '' last_name,
'' email, 0 address_id, activebool, create_date, last_update, 0 active, * FROM country
UNION ALL
SELECT *, 0 country_id, '' country, last_update FROM customer
I don't know how to do that for certain data types like boolean type and date/time type like date and timestamp. I'm new to postgresql. So can anyone tell me what values should I put for the data types I mentioned? Sorry for my english.

I hope this can help.
I Tried those on psql they work fine:
For timestamp
SELECT '-infinity' AS "test" UNION SELECT '0001-01-01 00:00:00'::timestamp;
For boolean
SELECT null AS "test" UNION SELECT 0::boolean;
SELECT 'true' AS "test" UNION SELECT 0::boolean;

Related

postgres how to insert values with 2 selects

I'm trying to do a query on Postgres but it's not working. I'd like to create an insert query with 2 select:
Example :
INSERT INTO table1 (id_1, id_2)
SELECT id from table_2 where code='01',
SELECT id from table_2 where code='02';
I don't find the good syntax for this.
I believe below query will works for your use case
INSERT INTO stats(totalProduct, totalCustomer, totalOrder)
VALUES(
(SELECT COUNT(*) FROM products),
(SELECT COUNT(*) FROM customers),
(SELECT COUNT(*) FROM orders)
);
you can changes query accordingly
You can add one more SELECT to achieve this
INSERT INTO table_1 (id_1, id_2)
SELECT
(SELECT id FROM table_2 WHERE code = '01') AS Id_1,
(SELECT id FROM table_2 WHERE code = '02') AS Id_2;
Or you may try with CASE expression:
INSERT INTO table1 (id_1, id_2)
SELECT MAX(CASE WHEN code = '01' THEN id ELSE 0 END) AS Id_1,
MAX(CASE WHEN code = '02' THEN id ELSE 0 END) AS Id_2
FROM table_2
Please refer to the working fiddle on db<>fiddle

Learning Pivoting in TSQL

I feel that this should be simple, but all the pivots I find seem to be more complicated than what I am looking for, so any help or re-direction would be much appreciated.
I have ‘ID_code’ and ‘product_name’ and I am looking for mismatched product names and have them put next to each other in a row as opposed to in a column like this:
Select distinct ID_Code, product_name
From table
Where ID_Code in
(Select ID_Code from table
Group by ID_Code
Having count(distinct product_name) <> 1)
I would like a table set out as
ID_Code Product_name1 Product_name2 Product_name3
Thanks very much, and have a Happy New Year!
This should remove the duplicates but still returns one result if the product_name has a match.
;with testdata as(
SELECT '1' as ID_Code, 'bike' as product_name
UNION ALL SELECT '1', 'biker'
UNION ALL SELECT '1', 'bike'
UNION ALL SELECT '2', 'motorbike'
UNION ALL SELECT '2', 'motorbike'
UNION ALL SELECT '2', 'motorbike'
UNION ALL SELECT '2', 'motrbike'
UNION ALL SELECT '2', 'motorbiker'
)
--added this section to return distinct products
,cte as(
SELECT * FROM testdata d1
INTERSECT
SELECT * FROM testdata d2
)
SELECT --DISTINCT --Use DISTINCT here if need to return just one line per ID_Code
ID_Code
,product_name = STUFF((SELECT ', ' +
--Added this to track product_names for each ID_Code
t2.product_name + '_' + cast(ROW_NUMBER() OVER (PARTITION BY ID_Code ORDER BY product_name) as varchar(100))
FROM cte t2
WHERE t2.ID_Code = cte.ID_Code
FOR XML PATH('')), 1, 2, '')
FROM cte
Example here: db<>fiddle
More info about INTERSECT should this not be what works in this scenario.
Your expected output appears to be somewhat inflexible, because we may not know exactly how many columns/products would be needed. Instead, I recommend and rolling up the mismatched products into a CSV string for output.
SELECT
ID_Code,
STUFF((SELECT ',' + t2.product_name
FROM yourTable t2
WHERE t1.ID_Code = t2.ID_Code
FOR XML PATH('')), 1, 1, '') products
FROM your_table t1
GROUP BY
ID_Code
HAVING
MIN(product_name) <> MAX(product_name); -- index friendly
Demo

T-SQL Replacing Nulls with Empty String

I have the following union query:
select
'type1' as type,
id,
add_date
from Table A
where type = type1
union all
select
'type2' as type,
id,
'' as add_date
from Table B
Since add_date isn't applicable to type 2, it is providing 1900-01-01 00:00:00.000 for any records returned. I could change the statement from '' as add_date to NULL as add_date, but the user is asking if I can remove the null from the report and leave the result as an empty string where applicable. What is the best way to accomplish this? Thanks.!
You can use null and cast the result as a string with the ISNULL function applied:
SELECT [type], id, ISNULL(CAST(add_date as VARCHAR), '') AS add_date
FROM (
SELECT 'type1' as [type]
,id
,add_date
FROM TableA
UNION
SELECT 'type2' as [type]
,id
,null as add_date
FROM TableB
) inside_query
This will allow you to provide blanks instead of 1/1/1900 or NULL keyword. You can also change the CAST to a CONVERT if you need to provide specific date formatting.
try this:
select
'type1' as type,
id,
CAST(add_date AS VARCHAR) as add_date
from Table A
where type = type1
union all
select
'type2' as type,
id,
'' as add_date
from Table B

Most effective way to get value if select count(*) = 1 with grouping

Lets say I have table with ID int, VALUE string:
ID | VALUE
1 abc
2 abc
3 def
4 abc
5 abc
6 abc
If I do select value, count(*) group by value I should get
VALUE | COUNT
abc 5
def 1
Now the tricky part, if there is count == 1 I need to get that ID from first table. Should I be using CTE? creating resultset where I will add ID string == null and run update b.ID = a.ID where count == 1 ?
Or is there another easier way?
EDIT:
I want to have result table like this:
ID VALUE count
null abc 5
3 def 1
If your ID values are unique, you can simply check to see if the max(id) = min(id). If so, then use either one, otherwise you can return null. Like this:
Select Case When Min(id) = Max(id) Then Min(id) Else Null End As Id,
Value, Count(*) As [Count]
From YourTable
Group By Value
Since you are already performing an aggregate, including the MIN and Max function is not likely to take any extra (noticeable) time. I encourage you to give this a try.
The way I would do it would indeed be a CTE:
using #group AS (SELECT value, Count(*) as count from MyTable GROUP BY value HAVING count = 1)
SELECT MyTable.ID, #group.value, #group.count from MyTable
JOIN #group ON #group.value = MyTable.value
When using group by, after the group by statement you can use a having clause.
So
SELECT [ID]
FROM table
GROUP BY [VALUE]
HAVING COUNT(*) = 1
Edit: with regards to your edited question: this uses some fun joins and unions
CREATE TABLE #table
(ID int IDENTITY,
VALUE varchar(3))
INSERT INTO #table (VALUE)
VALUES('abc'),('abc'),('def'),('abc'),('abc'),('abc')
SELECT * FROM (
SELECT Null as ID,VALUE, COUNT(*) as [Count]
FROM #table
GROUP BY VALUE
HAVING COUNT(*) > 1
UNION ALL
SELECT t.ID,t.VALUE,p.Count FROM
#table t
JOIN
(SELECT VALUE, COUNT(*) as [Count]
FROM #table
GROUP BY VALUE
HAVING COUNT(*) = 1) p
ON t.VALUE=p.VALUE
) a
DROP TABLE #table
maybe not the most efficient but something like this works:
SELECT MAX(Id) as ID,Value FROM Table WHERE COUNT(*) = 1 GROUP BY Value

Quotation mark incorrect when using crosstab() in PostgreSQL

I have a table t1 as below:
create table t1 (
person_id int,
item_name varchar(30),
item_value varchar(100)
);
There are five records in this table:
person_id | item_name | item_value
1 'NAME' 'john'
1 'GENDER' 'M'
1 'DOB' '1970/02/01'
1 'M_PHONE' '1234567890'
1 'ADDRESS' 'Some Addresses unknown'
Now I want to use crosstab function to extract NAME, GENDER data, so I write a SQL as:
select * from crosstab(
'select person_id, item_name, item_value from t1
where person_id=1 and item_name in ('NAME', 'GENDER') ')
as virtual_table (person_id int, NAME varchar, GENDER varchar)
My problem is, as you see the SQL in crosstab() contains condition of item_name, which will cause the quotation marks to be incorrect.
How do I solve the problem?
To avoid any confusion about how to escape single quotes and generally simplify the syntax, use dollar-quoting for the query string:
SELECT *
FROM crosstab(
$$
SELECT person_id, item_name, item_value
FROM t1
WHERE person_id = 1
AND item_name IN ('NAME', 'GENDER')
$$
) AS virtual_table (person_id int, name varchar, gender varchar);
See:
Insert text with single quotes in PostgreSQL
And you should add ORDER BY to your query string. I quote the manual for the tablefunc module:
In practice the SQL query should always specify ORDER BY 1,2 to ensure
that the input rows are properly ordered, that is, values with the
same row_name are brought together and correctly ordered within the
row. Notice that crosstab itself does not pay any attention to the
second column of the query result; it's just there to be ordered by,
to control the order in which the third-column values appear across the page.
See:
PostgreSQL Crosstab Query
Double your single quotes to escape them:
select * from crosstab(
'select person_id, item_name, item_value from t1
where person_id=1 and item_name in (''NAME'', ''GENDER'') ')
as virtual_table (person_id int, NAME varchar, GENDER varchar)