View Sidebar

Brian Mayer: product and marketing strategy consultant.

I am based in New York City and I update my blog infrequently. About me.
What I Learned This Year

What I Learned This Year

It is my birthday. So therefore it is time to check in and summarize what I learned since last year.

The biggest thing I learned was to double down on my commitment to avoiding toxic people. The second thing I learned (or re-affirmed, because at this point the lessons are the same you just keep learning them in new ways) is to guard my schedule with my life. All things being equal, time is the only restrictive asset any of us have. It’s also important, I have found, to schedule time for myself with no agenda.

Finally, I have been taking an unabashed honesty approach to relationships with other people that has worked really well. At some point this year I stopped trying to change the terms of relationships with people according to what I think would make them work better, and just accepted that I’d rather lose a connection with someone than have the connection based on a dishonest foundation. People will just have to take me as I am or not take me at all. And, of course, on the flip side, it’s not worth trying to change other people. Take them as they are, or don’t take them at all.

There are enough new friends in the world out there who won’t need to change their world for you, or visa versa. Go out and meet them.

February 17, 20190 commentsRead More
Toxic People

Toxic People

Every year, especially on my birthday, which happens to be tomorrow, I re-avow to myself to keep toxic people out of my life. It also happens that I was reading a passage today in The 48 Laws of Power by Robert Greene, whose chapter title is literally “INFECTION: AVOID THE UNHAPPY AND UNLUCKY.” From that passage:

The infecting-character type…stems from an inward instability that radiates outward, drawing disaster upon itself. There is almost a desire to destroy and unsettle. You could spend a lifetime studying the pathology of infecting characters, but don’t waste your time–just learn the lesson. When you suspect you are in the presence of an infector, don’t argue, don’t try to help, don’t pass the person on to your friends, or you will become enmeshed. Flee the infector’s presence or suffer the consequences.

What I love about this passage is it perfectly sums up the problem with toxic people: not that they are particularly bad people, or even that they are toxic to everyone, but that they are toxic to you.

As I get older and maybe a bit wiser, I learn how important it is to be strategically selfish about one’s own time and sanity. It’s impossible to get anything done if you are spending your efforts on fixing other people. True friends don’t demand more of your time and care than they give in return. Toxic people only take.

I don’t relish the notion that people don’t all equally deserve love, happiness, or attention. Which is not to say people deserve these things, but that they are not owed them by me, at my expense. The toxic people in your life are those people who take energy away from you.

Follow the advice of Greene and Marie Kondo and so many others, and make careful inventory of the people in your life, asking if they add to your overall happiness. If not, even if they are merely neutral, question how much time and energy you need to spend around that person. It’s not mean. It’s essential for your own wellbeing.

February 16, 20190 commentsRead More
National Emergency

National Emergency

Well, it happened. Today we all woke up in a world where the President of the United States presumably has the power to declare a national emergency to spend any money on any project he or she wants, without Congress.

I wrote previously about this being the red line even Republicans would have to stand up to, on principle if nothing else. Over the weekend we’ll see if these principles mean anything. In the meantime, I hope the Democrats have the ability and strength to fight this blatant violation of constitutional law.

If not, we will soon find ourselves not living in the fake dictatorship imagined by panicked liberals over the last two years, but an actual one where the chief executive has unchecked power. And given what he has talked about doing without power, it is hard to imagine that what he actually does with it ends well, for anyone.

February 15, 20190 commentsRead More
Valentine’s Day

Valentine’s Day

There’s nothing like watching all your single friends getting depressed around February 13 or so when they realize they don’t have any Valentine’s Day plans.

Though there really was a St. Valentine and his matyrdom has been celebrated by Catholics for 1500 years, it is only recently that it became the Hallmark holiday of all Hallmark holidays. In reality, it’s just an excuse to charge more for restaurant reservations.

It’s weird that a religious festival in honor of a 3rd-century saint who was executed for converting people to Christianity should become, in the modern day, an atheistic orgy of heart-themed commercialism. But I suppose, in the American sphere at least, people need excuses to be romantic. Or at least an excuse to pretend to be romantic lest the whole relationship fizzle out.

My recommendation to single friends on Valentine’s Day: remember that on February 14 in the year 270, the actual St. Valentine was beaten with clubs and then beheaded in front of a crowd. Oh, and you can visit said head in Rome if you are so inclined. And maybe his fingers are in a church in Dublin, though no one is really sure.

That ought to cure you of the notion that you “should” be celebrating this holiday with a significant other instead of doing what you normally do: get drunk on white wine at home and watch Netflix.

And for my friends in relationships: it’s a lot cheaper to save your dinner plans for this Friday. Enjoy ❤️

February 14, 20190 commentsRead More
High Beta

High Beta

I was extremely happy to lose an investment today. It was a small-cap investment in what was essentially a penny stock, though traded on a major exchange. The best part about these investments is that the downside is small, but the upside is uncapped. There’s a limited number of investments of this type that anyone should keep in a sensible portfolio. But it’s good to hold them for unexpected “black swan” events. In any event, I lost this one. But I’m confident it was still the right choice.

February 13, 20190 commentsRead More
How to Turn a Status History Table into a Daily Status Table Using PostgreSQL, with the Help of Some Window Functions

How to Turn a Status History Table into a Daily Status Table Using PostgreSQL, with the Help of Some Window Functions

Let’s say you have a table of the format:

object_id |        timestamp      | old_status | new_status
32049     | 2018-02-01 14:32:22   | TRUE       | FALSE
32049     | 2018-03-02 12:30:20   | FALSE      | TRUE
32049     | 2018-03-04 18:30:50   | TRUE       | FALSE
52053     | 2019-02-09 00:30:50   | FALSE      | TRUE
52053     | 2019-02-09 00:30:53   | TRUE       | FALSE
52053     | 2019-02-10 16:30:56   | FALSE      | TRUE

Where each entry, for simplicity’s sake, is one change in boolean status for the object: TRUE | FALSE or FALSE | TRUE. This is a fairly common history table that you’d find in the database of many applications, for example a profile settings history with a search engine visibility toggle.

Let’s say that you want to build a lookup table in your warehouse so that you can easily discover whether, on any given day, the toggle in question is set to a specific state, in this case TRUE. This happens to be the situation we found ourselves in at WayUp in order to make it easy to know whether a job was active during a given period.

This is the output we’re going for, where every row is a date where the object is active. If the object is not active during that date, there would be no entry for it.

For the example above, our work should yield the following. Since object 32053 was set to true on 2/10/2019, it is currently also true on 2/12/2019. We also will assume that both objects were created on 1/31/2018.

object_id | date
32049     | 2018-01-31 (creation as active)
32049     | 2018-02-01
32049     | 2018-03-02
32049     | 2018-03-03
32049     | 2018-03-04
52053     | 2019-02-09
52053     | 2019-02-10
52053     | 2019-02-11
52053     | 2019-02-12 (today)

How do you do it?

It’s a deceptively hard problem, because the result we’re going for is a lookup table where we need dates in between, and inclusive of, the toggles that are set to TRUE. We also need dates after the last toggle was set to TRUE up through the current date. If the history table doesn’t include the initial state the object was created in (which is very often the case), we will need to handle that case as well.

Step One: Build a Date-Based History Table

We’ll first need the history of this object by date, because that’s the final format we’ll be storing the table in. (Even if your final use case for this lookup will be rollups by month or quarter, if you have it broken out by date, it will make rollups easy using SELECT DISTINCT across any time period.)

Let’s go back to our original sample table.

object_id |        timestamp      | old_status | new_status
32049     | 2018-02-01 14:32:22   | TRUE       | FALSE
32049     | 2018-03-02 12:30:20   | FALSE      | TRUE
32049     | 2018-03-04 18:30:50   | TRUE       | FALSE
52053     | 2019-02-09 00:30:50   | FALSE      | TRUE
52053     | 2019-02-09 00:30:53   | TRUE       | FALSE
52053     | 2019-02-10 16:30:56   | FALSE      | TRUE

The first thing we do, is append the current status of the object at the current time. The reason is, we need to eventually add active date rows for objects which were previously set to active, and thus are still active today. This can be done with a simple union, with a NULL for new_status.

object_id |        timestamp            | old_status | new_status
32049     | 2018-02-01 14:32:22         | TRUE       | FALSE
32049     | 2018-03-02 12:30:20         | FALSE      | TRUE
32049     | 2018-03-04 18:30:50         | TRUE       | FALSE
32049     | 2019-02-12 23:59:43 (now)   | FALSE      | NULL
52053     | 2019-02-09 00:30:50         | FALSE      | TRUE
52053     | 2019-02-09 00:30:53         | TRUE       | FALSE
52053     | 2019-02-10 16:30:56         | FALSE      | TRUE
52053     | 2019-02-12 23:59:43 (now)   | TRUE       | NULL

Now it’s easy to build a day-by-day history table using some window functions. Remember the DISTINCT, otherwise you will get duplicate rows.

SELECT DISTINCT
   object_id
   , DATE(timestamp) AS date
   , FIRST_VALUE(old_status) OVER(PARTITION BY object_id,DATE(timestamp) ORDER BY timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS old_status
   , LAST_VALUE(new_status) OVER(PARTITION BY object_id,DATE(timestamp) ORDER BY timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS new_status
FROM status_history

The output will give you the first old status and last new status of each date. Note object #52053 on 2/9: although it was active on this date, it started and ended as inactive. At some point, we’ll need to remember to account for this use case.

object_id |    date    | old_status | new_status
32049     | 2018-02-01 | TRUE       | FALSE
32049     | 2018-03-02 | FALSE      | TRUE
32049     | 2018-03-04 | TRUE       | FALSE
32049     | 2019-02-12 | FALSE      | NULL
52053     | 2019-02-09 | FALSE      | FALSE
52053     | 2019-02-10 | FALSE      | TRUE
52053     | 2019-02-12 | TRUE       | NULL

Step Two: Prepare the Join

You can begin to see now what we’ll need to do. We’ll need to insert new rows for each object between every row where new_status is TRUE and old_status is TRUE. These rows will need to be bounded by date. We already have an upper bound: the “date” column. But we need to add a lower bound as well–which means we need to know for each row what the previous date was that the toggle was changed. This can be accomplished with the LAG() window function.

You may realize at this point we have one more problem. For the first entry for each object, there will be no previous date: it will be NULL. This gives us an opportunity to address another use case: when the objects are created TRUE without the history table being altered. So we’ll replace that first prev_toggle cell for each object with the creation date for each object. We’re also going to offset this date by one. You’ll see why in the next step.

SELECT
   object_id
   , date
   , old_status
   , new_status
   , COALESCE(
      LAG(date,1) OVER(PARTITION BY object_id ORDER BY date)
      , DATE(object.created_at) - INTERVAL '1 DAY'
    ) AS prev_toggle
FROM daily_status
JOIN object USING (object_id)

The output is ready now to be easily transformed using a simple join.

object_id |    date    | old_status | new_status | prev_toggle
32049     | 2018-02-01 | TRUE       | FALSE      | 2018-01-30
32049     | 2018-03-02 | FALSE      | TRUE       | 2018-02-01
32049     | 2018-03-04 | TRUE       | FALSE      | 2018-03-02
32049     | 2019-02-12 | FALSE      | NULL       | 2018-03-04
52053     | 2019-02-09 | FALSE      | FALSE      | 2018-01-30
52053     | 2019-02-10 | FALSE      | TRUE       | 2019-02-09
52053     | 2019-02-12 | TRUE       | NULL       | 2019-02-10

Step Three: Join and Union

We’re now going to do our join in two steps. First, we’re going to use a cross-join to add all the dates before the rows where old_status is TRUE. We know for a fact that every one of these dates is active.

object_id |    date    | old_status | new_status | prev_toggle
32049     | 2018-01-31 < ======== HERE
32049     | 2018-02-01 | TRUE       | FALSE      | 2018-01-30
32049     | 2018-03-02 | FALSE      | TRUE       | 2018-02-01
32049     | 2018-03-03 < ======== HERE
32049     | 2018-03-04 | TRUE       | FALSE      | 2018-03-02
32049     | 2019-02-12 | FALSE      | NULL       | 2018-03-04
52053     | 2019-02-09 | FALSE      | FALSE      | 2018-01-30
52053     | 2019-02-10 | FALSE      | TRUE       | 2019-02-09
52053     | 2018-02-11 < ======== HERE
52053     | 2019-02-12 | TRUE       | NULL       | 2019-02-10

Then, we’re going to append all the dates in which a toggle was set to TRUE at some point. For this we’ll go back to our original status change table.

For this join, we’ll need a list of all objects cross-joined against all dates. This is easy using an all_dates table you can generate with a csv for this purpose.

SELECT
   object_id
   , date
FROM object
JOIN all_dates
ON all_dates.date >= DATE(object.created_at)
AND all_dates.date <= DATE(GETDATE())

This will yield a potentially massive table even truncating the dates as shown above. It should perform fine up to a couple million objects though–OK for most practical purposes.

object_id | date
32049     | 2018-01-31
32049     | 2018-02-01
32049     | 2018-02-02
...       | ...
32049     | 2019-02-12
52053     | 2018-01-31
52053     | 2018-02-01
52053     | 2018-02-02
...       | ...
52053     | 2019-02-12

Now, the join and the union can be done inside the same query. Remember we’re using the JOIN to create additional rows in before status_old is TRUE, using the prev_toggle field as an upper bound. The reason we had offset the creation date by one, is so we could fill in rows between creation date and a TRUE toggle, using the same bounded method. The UNION is used to append those dates in which we know the toggle to be active, and remove duplicates.

SELECT
   daily_status_with_prev.object_id
   , all_time_objects.date AS active_date
FROM daily_status_with_prev
JOIN all_time_objects ON
   daily_status_with_prev.old_status IS TRUE
   AND all_time_objects.date < daily_status_with_prev.date
   AND all_time_objects.date > daily_status_with_prev.prev_toggle
   AND all_time_objects.object_id = daily_status_with_prev.object_id

UNION

SELECT
   status_history.object_id
   , DATE(status_history.timestamp) AS active_date
FROM status_history
WHERE old_status IS TRUE
OR new_status IS TRUE

The result is exactly what we were aiming for! One row per date each object was active.

object_id | date
32049     | 2018-01-31
32049     | 2018-02-01
32049     | 2018-03-02
32049     | 2018-03-03
32049     | 2018-03-04
52053     | 2019-02-09
52053     | 2019-02-10
52053     | 2019-02-11
52053     | 2019-02-12

Used correctly, this new table is extremely powerful for analytics and in rollups. It’s hard to make but well worth it!

February 12, 20190 commentsRead More
Whole Foods is out of Almond Mylk Again – an Original Poem

Whole Foods is out of Almond Mylk Again – an Original Poem

Whole Foods is out of almond mylk again
What am I supposed to put on my cereal
People don’t know how hard it is
To not be able to make chia seed pudding
And since I am lactose intolerant
And became proudly gluten free
No cow milk.
No goat milk.
No soy milk.
No oat milk.
And I have a deadly cashew allergy.

Whole Foods has no kombucha once again
Where else am I going to get anti-oxidants
Its natural properties kill deadly bacteria
Everyone at work drinks it every day
It’s usually in the coconut water aisle
With the ten dollar fair trade cold brew
I guess it’s no use
I’ll have pomegranate juice
What’s a wellness conscious consumer to do?

Without my healthy food
I’m in a rotten mood
I’m in a panic
If I can’t buy organic
I need some tea
That is fair trade and GMO free…

Whole Foods is out of almond mylk again
They stopped selling asparagus water
They used to have mochi at the sushi bar
What happened to the sunflower seaweed
They keep changing the food I’m supposed to eat
I guess that’s just the way it goes
There’s nothing to be cooked
And Instacart is booked
I guess I’ll go to Trader Joe’s.

February 11, 20190 commentsRead More
Breaking a Sugar Addiction

Breaking a Sugar Addiction

As of February 8, I successfully accomplished a 31-day sugar fast, which is probably the first time in my life I’ve actually had any sort of self control when it comes to diet.

I learned a couple things about myself during this month. The first thing I learned was that I was actually addicted to sugar, and didn’t merely enjoy it. Around day 7, I went through several days of withdrawal pains which finally subsided. When I finally had sugar again (a grape, after over a month), my sweet receptors went into overdrive and I suddenly craved even more. I confess I went a little overboard during my ski trip, but even when I was “allowed” to eat it again I consumed much less than I would have before the fast.

I learned that I have a lot more control about what I choose to eat than I thought. At first, it was difficult to avoid sugar. It is, after all, in almost everything. But once I got used to my high-fat diet of cheese, meat and veggies, I found it easy to avoid. Now, post-fast, I’m noticing that it’s far easier to just make the choice to avoid it; in fact, I’m noticing as I stare at the one cookie on my plate, that it is a deliberate choice I made to eat sugar this time. I control it, and it doesn’t control me.

The final thing I learned is that, loathe as I am to admit it, sugar isn’t really that necessary or even desirable. This is hard for me to say, because I literally swear by my sweet tooth. Dessert is the best part of every meal. I grew up on candy. But at the same time, without it I got just as much done (arguably more). I had very little caffeine (as my usual caffeine intake comes with copious amounts of sugar) and yet I had more energy. And I’m pretty sure I ate less overall.

For those of you considering it, I highly recommend just trying to go off sugar for at least two weeks. It’s not that hard to accomplish, and once you do you may find that you don’t need it, or even want it, as much as you think.

February 10, 20190 commentsRead More
Skiing

Skiing

I have spent the weekend enjoying the company of friends and the charm of Park City, but most of all I have spent the weekend skiing.

I learned how to ski on family vacations as a kid, stopped for over a decade, and only recently took it up again. It’s nice to regain an affection for something prominent in childhood later in life.

I truly enjoy the rush of wind while careening down the slopes, the challenge of turning and balancing simultaneously, watching out for obstacles and other skiers, and the feeling of speed. Skiing with friends is fun, but even if you are skiing with friends, you really are ever only skiing alone. It’s hard not to feel a connection with the mountain.

Skiing is an unusual recreation. It’s not practical enough to be most people’s main sport and too expensive to do it frequently, especially frequently enough to become good at it. For us vacation and weekend skiers, we don’t do it for the workout. We do it for the challenge, and we do it for the scenery. And we do it for the fun.

I’d like to become really good at it one day. But the chances of that are slim unless I one day find myself living near a mountain. In the meantime, I’m just a weekender. I’m ok with that.

February 9, 20190 commentsRead More
The Greatest Headline Ever Written

The Greatest Headline Ever Written

The news today speaks for itself. Jeff Bezos has revealed that the National Enquirer, led by David Pecker, is attempting to extort him over some…personal photos allegedly obtained of Bezos.

There will be much coverage of this news. The only thing I wish to assert here is, the circumstances and the name of the alleged extortionist have yielded the greatest headline every written for the American news.

February 8, 20190 commentsRead More