mysql update a table with counts of another table - mysql-error-1054

if you could help I would be very thankful.
there are two tables, customers and lead_report
I want to take the counts from the first column and place them in the matching row of the second column.
select leadsource,count(*) from customers where leadsource is not null and leadsource !="" group by leadsource;
select leadsource,count(*) from customers where leadsource is not null and leadsource !="" group by leadsource;
+---------------------+----------+
| leadsource | count(*) |
+---------------------+----------+
| Show 2014 | 2 |
| Show 2013 | 4 |
| By Me | 1 |
+---------------------+----------+
select source,leads from lead_report;
+---------------------+-------+
| source | leads |
+---------------------+-------+
| Show 2014 | 0 |
| Show 2013 | 0 |
| By Me | 0 |
+---------------------+-------+
update lead_report leads inner join
(select leadsource,count(*) from customers where leadsource is not null and leadsource !="" group by leadsource)
customers using (leadsource) set lead_report.leads = customers.leadsource;
ERROR 1054 (42S22): Unknown column 'leadsource' in 'from clause'

update lead_report lr join
(select leadsource, count(*) cnt from customers
where leadsource is not null and leadsource !="" group by leadsource) cust
ON lr.source=cust.leadsource
SET lr.leads=cust.cnt;

Related

SQL Server: GROUP BY with multiple columns produces duplicate results

I'm trying to include a 3rd column into my existing SQL Server query but I am getting duplicate result values.
Here is an example of the data contained in tb_IssuedPermits:
| EmployeeName | Current |
|--------------|---------|
| Person A | 0 |
| Person A | 0 |
| Person B | 1 |
| Person C | 0 |
| Person B | 0 |
| Person A | 1 |
This is my current query which produces duplicate values based on 1 or 0 bit values.
SELECT EmployeeName, COUNT(*) AS Count, [Current]
FROM tb_IssuedPermits
GROUP BY EmployeeName, [Current]
| EmployeeName | Count | Current |
|--------------|-------|---------|
| Person A | 2 | 0 |
| Person B | 1 | 0 |
| Person C | 1 | 0 |
| Person A | 1 | 1 |
| Person B | 1 | 1 |
Any ideas on how I can amend my query to have the following expected result? I want one result row per EmployeeName. And Current shall be 1, if for the EmployeeName exists a row with Current = 1, else it shall be 0.
| EmployeeName | Count | Current |
|--------------|-------|---------|
| Person A | 3 | 1 |
| Person B | 2 | 1 |
| Person C | 1 | 0 |
The result does not need to be in any specific order.
TIA
If your Current column contains the string values 'FALSE' and 'TRUE' you can do this
SELECT EmployeeName, Count(*) AS Count,
MAX([Current]) AS Current
FROM tb_IssuedPermits
GROUP BY EmployeeName
It's a hack but it works: MAX will get the TRUE from each group if there is one.
If your Current column is a BIT, cast to INT and cast back, as #ThorstenKettner suggested.
SELECT EmployeeName,
Count(*) AS Count,
CAST(MAX(CAST([Current] AS INT)) AS BIT) AS Current
FROM tb_IssuedPermits
GROUP BY EmployeeName
Alternatively, you can use conditional aggregation:
SELECT EmployeeName,
Count(*) AS Count,
CAST(COUNT(NULLIF(Current, 0)) AS BIT) AS Current
FROM tb_IssuedPermits
GROUP BY EmployeeName
you can do like this
SELECT EmployeeName, Count(1) AS Count,SUM(CAST([Current]AS INT)) AS Current FROM tb_IssuedPermits GROUP BY EmployeeName

SELECT To obtain results from two tables where a value occurs once only in a table column

Sorry I know this should be relatively simple and probably has been answered before, but I've got myself blocked on this and can't find a post here that matches.
I have two tables companies and contacts. A contact can be linked to 0 or 1 company, a company can have 1 or more contacts and MAY have one set as a 'primary contact'
companies(ccyID,ccyname,primconID)
________________________________________________
| ccyID | ccyname | PrimconID |
------------------------------------------------
| aaaaaaa | Company A | NULL |
| bbbbbbb | Company B | NULL |
| ccccccc | Company C | vvvvvvv |
________________________________________________
contacts(conID,firstname,lastname,ccyID)
__________________________________________________
| conID | first | last | companyID |
--------------------------------------------------
| zzzzzzz | Stand | Alone | NULL |
| yyyyyyy | Only | Contact | aaaaaaa |
| xxxxxxx | CompanyB | First | bbbbbbb |
| wwwwwww | CompanyB | Second | bbbbbbb |
| vvvvvvv | CompanyC | Only | ccccccc |
_________________________________________________
I need a SELECT that will return the companyID and contactID when the company has exactly one contact, AND does not have a PrimconID set i.e. for the above data I want returned
conID ccyID
----------------
yyyyyyy aaaaaaa
(The eventual idea is that I'm then going to update the tables to make the solitary contact for companies the primary contact)
Group contacts by company to keep only those with a count of 1 and make sure they are in the set of companies without primary contact:
select companyid, max(conid)
from contacts
group by companyid
having count(*) = 1
and companyid in (select ccyid from companies where primconid is null)
order by companyid;
I would use a join and group by:
select c.ccyid, max(co.conid)
from companies c join
contacts co
on co.companyid = c.ccyid
where c.PrimconID is null
group by c.ccyid
having min(co.conID) = max(co.conID);
As an update statement, you can do:
update c
set PrimconID = co.conid
from companies c join
(select co.companyid, max(co.conid) as conid
from contacts co
group by companyid
having min(co.conid) = max(co.conid)
) co
on co.companyid = c.ccyid
where c.PrimconID is null ;
Use a CTE to first identify all contacts having only a single company, and then join to the company table:
WITH cte AS (
SELECT ccyID, MAX(conID) AS conID
FROM contacts
GROUP BY ccyID
HAVING COUNT(*) = 1
)
SELECT
t.conID,
c.ccyID
FROM companies c
INNER JOIN cte t
ON c.ccyID = t.ccyID
WHERE
c.PrimconID IS NULL;
See the demo below to see the query working.
Demo

Getting date, and count of unique customers when first order was placed

I have a table called orders that looks like this:
+--------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| memberid | int(11) | YES | | NULL | |
| deliverydate | date | YES | | NULL | |
+--------------+---------+------+-----+---------+-------+
And that contains the following data:
+------+----------+--------------+
| id | memberid | deliverydate |
+------+----------+--------------+
| 1 | 991 | 2019-10-25 |
| 2 | 991 | 2019-10-26 |
| 3 | 992 | 2019-10-25 |
| 4 | 992 | 2019-10-25 |
| 5 | 993 | 2019-10-24 |
| 7 | 994 | 2019-10-21 |
| 6 | 994 | 2019-10-26 |
| 8 | 995 | 2019-10-26 |
+------+----------+--------------+
I would like a result set returning each unique date, and a separate column showing how many customers that placed their first order that day.
I'm having problems with querying this the right way, especially when the data consists of multiple orders the same day from the same customer.
My approach has been to
Get all unique memberids that placed an order during the time period I want to look at
Filter out the ones that placed their first order during the period by comparing the memberids that has placed an order before the timeperiod
Grouping by delivery date, and counting all unique memberids (but this obviously counts unique memberids each day individually!)
Here's the corresponding SQL:
SELECT deliverydate,COUNT(DISTINCT memberid) FROM orders
WHERE
MemberId IN (SELECT DISTINCT memberid FROM orders WHERE deliverydate BETWEEN '2019-10-25' AND '2019-10-26')
AND NOT
MemberId In (SELECT DISTINCT memberid FROM orders WHERE deliverydate < '2019-10-25')
GROUP BY deliverydate
ORDER BY deliverydate ASC;
But this results in the following with the above data:
+--------------+--------------------------+
| deliverydate | COUNT(DISTINCT memberid) |
+--------------+--------------------------+
| 2019-10-25 | 2 |
| 2019-10-26 | 2 |
+--------------+--------------------------+
The count for 2019-10-26 should be 1.
Appreciate any help :)
You can aggregate twice:
select first_deliverydate, count(*) cnt
from (
select min(deliverydate) first_deliverydate
from orders
group by memberid
) t
group by first_deliverydate
order by first_deliverydate
The subquery gives you the first order data of each member, then the outer query aggregates and counts by first order date.
This demo on DB Fiddle with your sample data returns:
first_deliverydate | cnt
:----------------- | --:
2019-10-21 | 1
2019-10-24 | 1
2019-10-25 | 2
2019-10-26 | 1
In MySQL 8.0, This can also be achieved with window functions:
select deliverydate first_deliverydate, count(*) cnt
from (
select deliverydate, row_number() over(partition by memberid order by deliverydate) rn
from orders
) t
where rn = 1
group by deliverydate
order by deliverydate
Demo on DB Fiddle
you have first to figure out when was the first delivery date:
SELECT firstdeliverydate,COUNT(DISTINCT memberid) FROM (
select memberid, min(deliverydate) as firstdeliverydate
from orders
WHERE
MemberId IN (SELECT DISTINCT memberid FROM orders WHERE deliverydate BETWEEN '2019-10-25' AND '2019-10-26')
AND NOT
MemberId In (SELECT DISTINCT memberid FROM orders WHERE deliverydate < '2019-10-25')
group by memberid)
t1
group by firstdeliverydate
Get the first order of each customer with NOT EXISTS and then GROUP BY deliverydate to count the distinct customers who placed their order:
select o.deliverydate, count(distinct o.memberid) counter
from orders o
where not exists (
select 1 from orders
where memberid = o.memberid and deliverydate < o.deliverydate
)
group by o.deliverydate
See the demo.
Results:
| deliverydate | counter |
| ------------------- | ------- |
| 2019-10-21 00:00:00 | 1 |
| 2019-10-24 00:00:00 | 1 |
| 2019-10-25 00:00:00 | 2 |
| 2019-10-26 00:00:00 | 1 |
But if you want results for all the dates in the table including those dates where there where no orders from new customers (so the counter will be 0):
select d.deliverydate, count(distinct o.memberid) counter
from (
select distinct deliverydate
from orders
) d left join orders o
on o.deliverydate = d.deliverydate and not exists (
select 1 from orders
where memberid = o.memberid and deliverydate < o.deliverydate
)
group by d.deliverydate

How to iterate on subgroups in SQL Server 2008?

I have one table looking like
Customer:
| CUSTOMER_ID | CUSTOMER_NAME | BANK_ID |
-----------------------------------------
| 1 | a | b |
| 2 | b1 | c |
| 3 | b1 | d |
| 4 | C | e |
| 5 | a | f |
| 6 | b1 | g |
I have a query that looks for all customer names that are not unique and group them together. It also assigns a row number to the rows in each group.
The output of this query is:
RowNumber|customer_id | customer_name |
1 | 1 | a |
2 | 5 | a |
1 | 2 | b1 |
2 | 3 | b1 |
3 | 6 | b1 |
I want to iterate on all the groups. For each group I want to join the members of the group with rows in a different table.Is there any way to operate on each sub group and apply business logic on the items in each sub group ?
for example: let's assume that for each group I want to leave the first customer if all the customers in this group live in the same place and work at the same place.
I have the following table:
|customer id | address | workplace-name |
|1 | street1 | work1|
|2 | street2 | work1|
|3 | street1 | work2|
|4 | street5 | work7|
|5 | street1 | work1|
|6 | street2 | work1|
You can notice that only the customers in the first group live and work at the same place (customers id: 1,5). If you look at the second group (customers id:2,3,6) - they don't all live and work at the same place.
The result of this query will be: customer id 5 as it's in the same group with customer id 5 and they both live and work in the same place. But customer 5 is the second in this group.
What's the easiest way to do it ?
Try this:
WITH A(Customer_id, Customer_name)
AS(SELECT Customer_id, Customer_name
FROM Customer
WHERE Customer_name IN
(SELECT Customer_name FROM Customer
GROUP BY Customer_name
HAVING COUNT(Customer_name) >1)
)
SELECT RANK() OVER (ORDER BY Customer_id ASC) AS RowNumber
, Customer_id, Customer_Name
FROM A
ORDER BY Customer_name, Customer_id;
Or you can also use JOIN for that
WITH A(Customer_id, Customer_name)
AS (SELECT c.Customer_id, c.Customer_name
FROM Customer c
JOIN
(SELECT Customer_id FROM Customer
WHERE Customer_name IN ( SELECT Customer_name FROM Customer
GROUP BY Customer_name
HAVING COUNT(Customer_name) >1)
) AS c1
ON c.Customer_id = C1.customer_id)
SELECT RANK() OVER (ORDER BY A.customer_id ASC) AS RowNumber
, Customer_id, Customer_Name
FROM A
ORDER BY Customer_name, Customer_id;
See this SQLFiddle
I couldn't find any way to do it in a single query. I've created a cursor that does what I want to do: Iterate on all the rows of one table, apply business logic and insert relevant rows to the output table.

if more than 1 match, do not return 'unknown'

I composed a monster query. I'm certain that it can be optimized, and I would more than appreciate any comments/guidance on the query itself; however, I have a specific question:
The data I am returning is sometimes duplicated on multiple columns:
+-------+------+----------+------+-------+--------+----------+-------+------+
| first | last | deaID | cert | count | npi | clientid | month | year |
+-------+------+----------+------+-------+--------+----------+-------+------+
| Alex | Jue | UNKNOWN | MD | 11 | 123123 | 102889 | 7 | 2012 |
| Alex | Jue | BJ123123 | MD | 11 | 123123 | 102889 | 7 | 2012 |
+-------+------+----------+------+-------+--------+----------+-------+------+
as you can see all of the fields are equal except for deaID
in this case, I would like to only return:
+------+-----+----------+----+----+--------+--------+---+------+
| | | | | | | | | |
+------+-----+----------+----+----+--------+--------+---+------+
| Alex | Jue | BJ123123 | MD | 11 | 123123 | 102889 | 7 | 2012 |
+------+-----+----------+----+----+--------+--------+---+------+
however, if there are no duplicates:
+-------+------+---------+------+-------+--------+----------+-------+------+
| first | last | deaID | cert | count | npi | clientid | month | year |
+-------+------+---------+------+-------+--------+----------+-------+------+
| Alex | Jue | UNKNOWN | MD | 11 | 123123 | 102889 | 7 | 2012 |
+-------+------+---------+------+-------+--------+----------+-------+------+
then i would like to keep it!
summary
if there are duplicates remove all records with 'deaID=unknown'; however, if there is only 1 match then return that match
question
how do i return unknown records IFF there is 1 match?
here is the monster query in case anybody is interested :)
with ctebiggie as (
select distinct
p.[IMS_PRESCRIBER_ID],
p.PHYSICIAN_NPI as MLISNPI,
a.CLIENT_ID,
p.MLIS_FIRSTNAME,
p.MLIS_LASTNAME,
p_address.IMS_DEA_NBR,
p.IMS_PROFESSIONAL_ID_NBR,
p.IMS_PROFESSIONAL_ID_NBR_src,
p.IMS_CERTIFICATION_CODE,
datepart(mm,a.RECEIVED_DATE) as [Month],
datepart(yyyy,a.RECEIVED_DATE) as [Year]
from
MILLENNIUM_DW_dev..D_PHYSICIAN p
left outer join
MILLENNIUM_DW_dev..F_ACCESSION_DAILY a
on a.REQUESTOR_NPI=p.PHYSICIAN_NPI
left outer join MILLENNIUM_DW_dev..D_PHYSICIAN_ADDRESS p_address
on p.PHYSICIAN_NPI=p_address.PHYSICIAN_NPI
where
a.RECEIVED_DATE is not null
--and p.IMS_PRESCRIBER_ID is not null
--and p_address.IMS_DEA_NBR !='UNKNOWN'
and p.REC_ACTIVE_FLG=1
and p_address.REC_ACTIVE_FLG=1
and DATEPART(yyyy,received_date)=2012
and DATEPART(mm,received_date)=7
group by
p.[IMS_PRESCRIBER_ID],
p.PHYSICIAN_NPI,
p.IMS_PROFESSIONAL_ID_NBR,
p.MLIS_FIRSTNAME,
p.MLIS_LASTNAME,
p_address.IMS_DEA_NBR,
p.IMS_PROFESSIONAL_ID_NBR,
p.IMS_PROFESSIONAL_ID_NBR_src,
p.IMS_CERTIFICATION_CODE,
datepart(mm,a.RECEIVED_DATE),
datepart(yyyy,a.RECEIVED_DATE),
a.CLIENT_ID
)
,
ctecount as
(select
COUNT (Distinct f.ACCESSION_ID) [count],
f.REQUESTOR_NPI,f.CLIENT_ID,
datepart(mm,f.RECEIVED_DATE) mm,
datepart(yyyy,f.RECEIVED_DATE)yyyy
from MILLENNIUM_DW_dev..F_ACCESSION_DAILY f
where
f.CLIENT_ID not in (select * from SalesDWH..TestPractices)
and DATEPART(yyyy,f.received_date)=2012
and DATEPART(mm,f.received_date)=7
group by f.REQUESTOR_NPI,
f.CLIENT_ID,
datepart(mm,f.RECEIVED_DATE),
datepart(yyyy,f.RECEIVED_DATE)
)
select ctebiggie.*,c.* from
ctebiggie
full outer join
ctecount c
on c.REQUESTOR_NPI=ctebiggie.MLISNPI
and c.mm=ctebiggie.[Month]
and c.yyyy=ctebiggie.[Year]
and c.CLIENT_ID=ctebiggie.CLIENT_ID
Assuming you have the base query, I will assign row_number and count by partition function over this resultset. Then on the outer select, if count is 1 then unknown is selected, else it is not selected.
SELECT first,
last,
deaID,
cert,
count,
npi,
clientid,
month,
year
FROM (
SELECT first,
last,
deaID,
cert,
count,
npi,
clientid,
month,
year,
ROW_NUMBER() OVER (PARTITION BY
first,last,cert,count,npi,clientid,month,year
ORDER BY CASE WHEN deaID = 'Unkown' THEN 0 ELSE 1 END,
deaID) AS RowNumberInGroup,
COUNT() OVER (PARTITION BY first,last,cert,count,npi,clientid,month,year)
AS CountPerGroup,
SUM(CASE WHEN deaID = 'Unkown' THEN 1 ELSE 0 END)
OVER (PARTITION BY first,last,cert,count,npi,clientid,month,year)
AS UnknownCountPerGroup
FROM BaseQuery
) T
WHERE (T.CountPerGroup = T.UnknownCountPerGroup AND T.RowNumberInGroup = 1) OR T.RowNumberInGroup > T.UnknownCountPerGroup
see this helps or not
select distinct main.col1,main.col2 ,
isnull(( select col3 from table1 where table1.col1=main.col1
and table1.col2=main.col2 and col3 <>'UNKNOWN'),'UNKNOWN')
from table1 main
Sample in Sql fiddle
or fair version of yours will be
SELECT distinct first,
last,
cert,
count,
npi,
clientid,
month,
year,
isnull(
select top 1 dealid from table1 intable where
intable.first=maintable.first and
intable.last=maintable.last and
intable.cert=maintable.cert and
intable.npi=maintable.npi and
intable.clientid=outtable.clientid and
intable.month=outtable.month and
intable.year=outtable.year
where dealid<>'UNKNOWN'),'UNKNOWN') as dealId
FROM table1 maintable